I was playing with CoffeeScript when I found myself writing the following lines and then looking at them in awe:
compose = (f, g) -> (x) -> f g x
curry = (f) -> (x) -> (y) -> f(x, y)
uncurry = (f) -> (x, y) -> (f x) y
How nice, did I think! Now, as an exercise, I thought I would generalize the curry and uncurry functions to n args, to obtain something similar to this:
curry2 = (f) -> (x) -> (y) -> f(x, y)
curry3 = (f) -> (x) -> (y) -> (z) -> f(x, y, z)
curry4 = (f) -> (x) -> (y) -> (z) -> (t) -> f(x, y, z, t)
And the same thing for uncurry:
uncurry2 = (f) -> (x, y) -> (f x) y
uncurry3 = (f) -> (x, y, z) -> ((f x) y) z
uncurry4 = (f) -> (x, y, z, t) -> (((f x) y) z) t
Writing the n-ary uncurry was not very hard:
uncurry = (n) -> (f) -> (args...) ->
if n == 1
f args[0]
else
((uncurry n - 1) f args.shift()) args...
On the other hand, I can’t figure out how to get the n-ary curry to work. I thought of implementing first a curry_list function that is the generalization of this suite:
curry_list2 = (f) -> (x) -> [x, y]
curry_list3 = (f) -> (x) -> (z) -> [x, y, z]
curry_list4 = (f) -> (x) -> (z) -> (t) -> [x, y, z, t]
Here’s the implementation:
curry_list = (n) ->
curry_list_accum = (n, accum) ->
if n
(x) ->
accum.push x
curry_list_accum n - 1, accum
else
accum
curry_list_accum n, []
And then I would just compose curry_list with function application to obtain currying. That’s what I tried to do:
curry = (n) ->
apply_helper = (f) -> (args) -> f args...
(f) -> compose (apply_helper f), (curry_list n)
But for some reason, it does not work. For exemple, trying to evaluate
curry(3)((a,b,c) -> a + b + c)(1)(2)(3)
yields the following error:
Function.prototype.apply: Arguments list has wrong type
Now after jotting some more notes I understand that trying to compose f with curry_list is incorrect. I do have the intuition that what I’m looking for is something that looks like this composition, but is not exactly that. Am I correct in thinking that?
Finally, what would be a correct implementation?
You are returning the composed function after
curry(3)((a,b,c) -> a + b + c), not the accumulator.That means
((args) -> f args...)is receiving a function as argument, your code doesn’t wait until the argument list is complete to callf.Maybe implement this without composition?