首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >CoffeeScript中的n-ary curry

CoffeeScript中的n-ary curry
EN

Stack Overflow用户
提问于 2011-12-04 12:54:39
回答 5查看 1.6K关注 0票数 16

当我在玩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是不正确的。我确实有一种直觉,我正在寻找的东西看起来像这个构图,但并不完全是那样的。我这样想对吗?

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

EN

回答 5

Stack Overflow用户

回答已采纳

发布于 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
票数 7
EN

Stack Overflow用户

发布于 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
票数 3
EN

Stack Overflow用户

发布于 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
票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/8373367

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档