Hi lispers,
So I'm a bit confused. I wrote this macro:
(defmacro curry (fn &rest args)
`(lambda (&rest argz)
(apply ,fn ,@args argz)))
and then I test it's expansion:
* (macroexpand-1 '(curry #'+ 1))
(LAMBDA (&REST ARGZ) (APPLY #'+ 1 ARGZ))
T
*
Looks good. But if I try this:
* ((curry #' + 1) 1)
I get:
; Error: Illegal function call.
but if I do:
* (funcall (curry #' + 1) 1)
2
*
It works. So if curry expands to a lambda function then why can't I
use ((curry #' + 1) 1)? Why must I funcall it? Am I messing up the
macro definition in some way?
Thanks,
Shawn
Moop <····@moop.moop> writes:
> So if curry expands to a lambda function then why can't I
> use ((curry #' + 1) 1)?
3.1.2.1.2: "If the car of a compound form is not a symbol, then
that car must be a lambda expression, in which case the compound
form is a lambda form."
In your compound form, the car is a macro form, not a lambda
expression. Common Lisp does not allow this. I think Scheme does.
Currying doesn't need to be implemented as a macro. Here's how I do
it, and apparently also Paul Graham as I saw this code in On Lisp as
well:
(defun curry (fn &rest args)
(lambda (&rest more-args)
(apply fn (append args more-args))))
You can just as easily implement right-currying:
(defun rcurry (fn &rest args)
(lambda (&rest more-args)
(apply fn (append more-args args))))
The only difference is the order of args to the append.
Hope this helps,
Justin Dubs
······@eos.ncsu.edu (Justin Dubs) writes:
> Currying doesn't need to be implemented as a macro. Here's how
> I do it, and apparently also Paul Graham as I saw this code in
> On Lisp as well:
>
> (defun curry (fn &rest args)
> (lambda (&rest more-args)
> (apply fn (append args more-args))))
The disadvantage is that this conses each time the curried
function is called.
Regards,
--
Nils G�sche
Ask not for whom the <CONTROL-G> tolls.
PGP key ID #xD26EF2A0
Nils Goesche <···@cartan.de> writes:
> ······@eos.ncsu.edu (Justin Dubs) writes:
>
> > Currying doesn't need to be implemented as a macro. Here's how
> > I do it, and apparently also Paul Graham as I saw this code in
> > On Lisp as well:
> >
> > (defun curry (fn &rest args)
> > (lambda (&rest more-args)
> > (apply fn (append args more-args))))
>
> The disadvantage is that this conses each time the curried
> function is called.
Well, it's easily possible to recursively rewrite this in a way that
does not cons [at curried function execution time, I mean] in at
least some implementations.
Kent M Pitman <······@world.std.com> writes:
> Nils Goesche <···@cartan.de> writes:
>
> > ······@eos.ncsu.edu (Justin Dubs) writes:
> >
> > > Currying doesn't need to be implemented as a macro. Here's how
> > > I do it, and apparently also Paul Graham as I saw this code in
> > > On Lisp as well:
> > >
> > > (defun curry (fn &rest args)
> > > (lambda (&rest more-args)
> > > (apply fn (append args more-args))))
> >
> > The disadvantage is that this conses each time the curried
> > function is called.
>
> Well, it's easily possible to recursively rewrite this in a way
> that does not cons [at curried function execution time, I mean]
> in at least some implementations.
Yes, but then you have more function calls each time you call the
curried function, and more closures consed up at the time you
build it.
Regards,
--
Nils G�sche
Ask not for whom the <CONTROL-G> tolls.
PGP key ID #xD26EF2A0
Nils Goesche <···@cartan.de> writes:
> Kent M Pitman <······@world.std.com> writes:
>
> > Nils Goesche <···@cartan.de> writes:
> >
> > > ······@eos.ncsu.edu (Justin Dubs) writes:
> > >
> > > > Currying doesn't need to be implemented as a macro. Here's how
> > > > I do it, and apparently also Paul Graham as I saw this code in
> > > > On Lisp as well:
> > > >
> > > > (defun curry (fn &rest args)
> > > > (lambda (&rest more-args)
> > > > (apply fn (append args more-args))))
> > >
> > > The disadvantage is that this conses each time the curried
> > > function is called.
> >
> > Well, it's easily possible to recursively rewrite this in a way
> > that does not cons [at curried function execution time, I mean]
> > in at least some implementations.
>
> Yes, but then you have more function calls each time you call the
> curried function, and more closures consed up at the time you
> build it.
Not if they are downward (i.e., dynamic-extent) closures and/or
downward conses.
Moop <····@moop.moop> writes:
> (defmacro curry (fn &rest args)
> `(lambda (&rest argz)
> (apply ,fn ,@args argz)))
>
> and then I test it's expansion:
>
> * (macroexpand-1 '(curry #'+ 1))
> (LAMBDA (&REST ARGZ) (APPLY #'+ 1 ARGZ))
> T
Kalle already answered your question, but I'd like to point out
that there are two further problems with this macro:
CL-USER 11 > (macroexpand-1 '(curry (foo 2) argz))
(LAMBDA (&REST ARGZ) (APPLY (FOO 2) ARGZ ARGZ))
T
First, (foo 2) is evaluated each time the curried function is
called; this /might/ be what you want, but I guess not.
Moreover, your local variable ARGZ might be clobbered. My
version of CURRY is:
(defmacro curry (f &rest curry-args)
(let ((args (gensym "ARGS"))
(fun (gensym "FUN"))
(curries (mapcar (lambda (arg)
(declare (ignore arg))
(gensym))
curry-args)))
`(let ((,fun ,f)
,@(mapcar #'list curries curry-args))
(lambda (&rest ,args)
(declare (dynamic-extent ,args))
(apply ,fun ,@curries ,args)))))
The DYNAMIC-EXTENT declaration might prevent that the list bound
to ,args is consed up on the heap in some implementations.
Regards,
--
Nils G�sche
Ask not for whom the <CONTROL-G> tolls.
PGP key ID #xD26EF2A0