当我在玩CoffeeScript时,我发现自己写了以下几行,然后惊叹地看着它们:
compose = (f, g) -> (x) -> f g x
curry = (f) -> (x) -> (y) -> f(x, y)
uncurry = (f) -> (x, y) -> (f x) y
我想,真是太好了!现在,作为练习,我想我应该将curry和uncurry函数推广到n个参数,以获得类似以下内容:
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)
对于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
编写n元uncurry并不是很难:
uncurry = (n) -> (f) -> (args...) ->
if n == 1
f args[0]
else
((uncurry n - 1) f args.shift()) args...
另一方面,我不知道如何让n-ary curry工作。我想先实现一个curry_list函数,它是这个套件的泛化:
curry_list2 = (f) -> (x) -> [x, y]
curry_list3 = (f) -> (x) -> (z) -> [x, y, z]
curry_list4 = (f) -> (x) -> (z) -> (t) -> [x, y, z, t]
下面是实现:
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, []
然后,我只需要将curry_list与函数应用程序组合在一起,就可以获得currying。这就是我想要做的:
curry = (n) ->
apply_helper = (f) -> (args) -> f args...
(f) -> compose (apply_helper f), (curry_list n)
但由于某些原因,它不起作用。例如,尝试评估
curry(3)((a,b,c) -> a + b + c)(1)(2)(3)
产生以下错误:
Function.prototype.apply:参数列表的类型错误
现在,在写了更多的笔记之后,我知道尝试用curry_list来组成f是不正确的。我确实有一种直觉,我正在寻找的东西看起来像这个构图,但并不完全是那样的。我这样想对吗?
最后,什么是正确的实现?
发布于 2011-12-04 15:16:49
在curry(3)((a,b,c) -> a + b + c)
之后返回的是组合函数,而不是累加器。
这意味着((args) -> f args...)
正在接收一个函数作为参数,您的代码不会等到参数列表完成后才调用f
。
也许在没有组合的情况下实现这一点?
accumulator = (n, accum, f) ->
return f accum... if n is 0
(x) ->
accum.push x
accumulator n - 1, accum, f
curry = (n) ->
(f) -> accumulator n, [], f
curry(3)((a,b,c) -> a + b + c)(1)(2)(3) # 6
发布于 2012-08-17 14:10:19
我认为没有比这更简单的了:
Function::curry = (n) ->
if n is 1 then @ else (x) => (=> @ x, arguments...).curry(n-1)
基本上,如果请求的参数大于1,那么它使用一个参数并返回另一个函数,并在此过程中构造一个函数梯子。它会一直这样做,直到数量为1,在这种情况下,它会爬上它创建的函数的阶梯。梯子将使用的参数添加到列表中,直到调用梯子顶部的函数,即用户提供的函数。
下面是我写的一些测试,如果你感兴趣的话:
add3 = ((a,b,c) -> a+b+c).curry 3
add3_1 = add3 1
add3_1_2 = add3_1 2
console.log add3_1(4)(5) is 10
console.log add3_1(4)(6) is 11
console.log add3_1_2(4) is 7
console.log add3_1(5)(5) is 11
发布于 2011-12-04 15:41:13
在我看来,这不像是作曲。您拥有的最后一个curry
实现似乎没有区分要执行curried的函数和该函数的参数,而这样的区别似乎相当重要。像这样怎么样?
curry = (n, f) ->
acc = []
helper = (x) ->
acc.push x
if acc.length is n then f acc... else helper
https://stackoverflow.com/questions/8373367
复制相似问题