| The spectre of currying is haunting the forum once again. I still think its a good idea for Arc, but only if we use the right kind of currying. True currying, in the mathematical sense (as used in ML, O'Caml etc.) works as follows: if f is a function of 3 arguments and f' is the curried form, then: f(x, y, z) = f'(x)(y)(z)
or in Arc: (f x y z) = (((f' x) y) z)
As Loup pointed out in his post, some kind of association would be required to make that practical: (f' x y z) => (((f' x) y) z)
Note that currying a function always produces a unary function, which in turn produces a value or another unary function, and so on. If your original function took n arguments, then you must call your curried version n times* to get the final value.In ANSI Common Lisp, pg defined a different way to do currying: (defun curry (fn &rest args)
#'(lambda (&rest args2)
(apply fn (append args args2))))
Note that this takes a function of many arguments, and returns a 'curried' version of many arguments, which also returns a function of many arguments, which returns a final value. So you always call the 'curried' function twice to get your value, regardless of the number of arguments.So this isn't really currying at all. It's something else, something useful, but not currying in the true sense. Now as people have pointed out, true currying simply doesn't work with variadic functions, because n is unknown at the time you curry your function. On the other hand, the pg style of currying works fine with any function. It has a downside: you always get your final value after the second call, so you can't gradually build up the arguments over many calls, but then does anyone really ever do that, and if you do, can't you just use the curry function again? So I think if Arc is going to have any kind of currying, it should have pg currying. I've suggested that if you use a [...] form without any underscores in it, then the function should be automatically pg-curried: (+ a b c d e) = ([+ a b] c d e)
I think this is a very concise notation and I'd use it quite often.Oh, and if you want to do real currying, here's a macro I created that does that with fixed-arity functions. The functions automatically associate to the left. I've hastily translated this from Lisp into Arc so it may have a few bugs: (mac cfn (parms . body)
`(curry ,(len parms) (fn ,parms ,@body)))
(def curry (parms-length fn (o old-args))
(rfn curried new-args
(withs (args (join old-args new-args)
args-length (len args))
(if (no new-args) curried
(is args-length parms-length) (apply fn args)
(> args-length parms-length) (err "Too many arguments.")
(curry parms-length fn args)))))
* I know you're not really applying the arguments to the same function each time, but to the function returned by the function returned by etc. etc., but I couldn't think of an easy way to express that. |