Subject: Re: How to simulate currying?
From: rpw3@rpw3.org (Rob Warnock)
Date: Sun, 15 Feb 2009 20:31:00 -0600
Newsgroups: comp.lang.lisp
Message-ID: <irSdnfbYI8d5UgXUnZ2dnUVZ_gudnZ2d@speakeasy.net>
Vsevolod <vseloved@gmail.com> wrote:
+---------------
| Slobodan Blazeski <slobodan.blaze...@gmail.com> wrote:
| > I want to make bind symbol _ to represent omitteed parameter so I
| > could make automatical currying using CLOS...
...
| For this purpose I have a reader macro, that implements what's present
| in Arc and Closure -- automatic variable substitution for one-argument
| lambdas. It's not, strictly speaking, currying, but it works for most
| of the practical cases (I use it very often):
|   (set-dispatch-macro-character #\# #\` ...[etc]... )
| So you get (funcall #`(plus 2 _) 3)
| A good feature is that it resembles (and thus reminds of) the simple
| function reader macro (#')...
+---------------

This seems to be a common meme!!  ;-}  My version of this hack
[appended below], which I too use very often in the REPL [but *NEVER*
in code files!!], is much more gross, but gives you up to nine args
plus a &REST arg, flagging both the reader macro and the args with "$"
[in homage to the Bourne Shell], e.g.:

    > (mapcar #$(/ $2 $1) '(1 2 3 4 5 6) '#1=(60 . #1#))

    (60 30 20 15 12 10)
    > 

The main reason I prefer it to a multiple-"_" style which some poeple
have proposed is that you can re-order the args as you choose [as above],
which also makes it convenient as a shorthand for simple instances of
DESTRUCTURING-BIND, e.g. (#$$3 12 34 56 78) ==> 56. It's also a shorthand
for CONSTANTLY:

    > (mapcar #$17.2 '(1 2 3 4) '#1=(60 . #1#))

    (17.2 17.2 17.2 17.2)
    > 

Its biggest current shortcoming is that the &REST arg "$*" [again,
copied from the Bourne Shell] only applies to args greater than "$9".

There was a long discussion thread here on this very topic a while
back [sorry, I don't remember when] in which it was proposed that
[and someone may have even posted code for!] the macro should do a
full tree walk of its body and collect both the highest "${n}" in the
code and also whether "$*" were used. That way, #$(list* $4 $1 $*)
would expand to:

    (lambda ($1 $2 $3 $4 &rest $*)
      (declare (ignore $2 $3))    ; or simpler, (ignorable $1 $2 $3 $4 $*)
	(list* $4 $1 $*))

Unfortunately, I don't remember when that better version was proposed
[or by whom], so all I have is my own crude hack [which I nevertheless
very often find useful when noodling around in the REPL]:

;;; SET-SHARP-DOLLAR-READER -- Experimental LAMBDA abbreviation
;;; SYNTAX: #$FORM
;;; Abbreviates (lambda (&optional $1 $2 $3 $4 $5 $6 $7 $8 $9 &rest $*) FORM)
;;; Within the FORM, args $1 ... $9 and $* are lambda-bound as positional
;;; and &REST parameters, respectively. Usually, but not always, FORM will be
;;; an S-expr, e.g. #$(car $3), but this is legal: #$FOO ==> (lambda () FOO),
;;; that is, (CONSTANTLY FOO). Likewise, #$$3 ==> #'THIRD.
;;;
;;; As a convenience for interactive use, in the special case that FORM is a
;;; list and (car FORM) is also a list, then an implicit PROGN is provided,
;;; e.g., #$((foo) (bar)) ==> (lambda (args...) (foo) (bar)).
;;;
(defun set-sharp-dollar-reader ()
  (flet ((sharp-dollar-reader (s c p)
	   (declare (ignore c p))
	   (let* ((form (read s t nil t)))
	     `(lambda (&optional $1 $2 $3 $4 $5 $6 $7 $8 $9 &rest $*)
		(declare (ignorable $1 $2 $3 $4 $5 $6 $7 $8 $9 $*))
		,@(if (and (consp form) (consp (car form)))
		    form
		    (list form))))))
    (set-dispatch-macro-character #\# #\$ #'sharp-dollar-reader)))

Enjoy.(?)  ;-}


-Rob

-----
Rob Warnock			<rpw3@rpw3.org>
627 26th Avenue			<URL:http://rpw3.org/>
San Mateo, CA 94403		(650)572-2607