CoffeeScript中的n-ary咖喱

Noé*_*ein 16 javascript functional-programming coffeescript

当我发现自己写下以下几行然后敬畏地看着它时,我正在玩CoffeeScript:

compose = (f, g) -> (x) -> f g x
curry = (f) -> (x) -> (y) -> f(x, y)
uncurry = (f) -> (x, y) -> (f x) y
Run Code Online (Sandbox Code Playgroud)

我觉得多好啊!现在,作为练习,我想我会将curry和uncurry函数推广到n args,以获得类似于此的东西:

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)
Run Code Online (Sandbox Code Playgroud)

不一致的是同样的事情:

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
Run Code Online (Sandbox Code Playgroud)

写n-ary uncurry并不是很难:

uncurry = (n) -> (f) -> (args...) ->
    if n == 1
        f args[0]
    else
        ((uncurry n - 1) f args.shift()) args...
Run Code Online (Sandbox Code Playgroud)

另一方面,我无法弄清楚如何让n-ary咖喱工作.我想先实现一个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]
Run Code Online (Sandbox Code Playgroud)

这是实施:

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, []
Run Code Online (Sandbox Code Playgroud)

然后我会用函数应用程序编写curry_list以获得currying.这就是我试图做的事情:

curry = (n) ->
    apply_helper = (f) -> (args) -> f args...
    (f) -> compose (apply_helper f), (curry_list n)
Run Code Online (Sandbox Code Playgroud)

但由于某种原因,它不起作用.例如,试图评估

curry(3)((a,b,c) -> a + b + c)(1)(2)(3)
Run Code Online (Sandbox Code Playgroud)

产生以下错误:

Function.prototype.apply:参数列表的类型错误

在记下一些笔记之后,我明白尝试用curry_list编写f是不正确的.我确实有直觉,我正在寻找的东西看起来像这个组合,但并非如此.我认为这是正确的吗?

最后,什么是正确的实现?

Ric*_*asi 7

您将返回组合函数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
Run Code Online (Sandbox Code Playgroud)