【问题标题】:Functional programming RamdaJs arity question函数式编程 RamdaJs arity 问题
【发布时间】:2019-08-02 22:59:26
【问题描述】:

我对 Ramda 和整个 FP 中的功能的准确性有疑问。

在 RamdaJs 中,一些函数接受 2,3 个参数,但其中一些是柯里化的(接受一个或两个参数并返回另一个函数)。

例如:

const isBlackCard = R.anyPass([isClub, isSpade]);
isBlackCard({rank: '10', suit: '♣'}); //=> true

anyPass - 返回另一个等待对象的函数。

R.reduce(R.add, 0, [1, 2, 3, 4])

在这种情况下,reduce 等待所有参数并返回结果 => 10

如果我按照前面的例子,为什么reduce和anyPass不一样,像这样:

const adder = R.reduce(R.add, 0);
const sum = adder([1, 2, 3, 4]); //10

这样它们看起来就一样了。

那么为什么它们不相似,何时创建一个或另一个是否有任何规则。

如果我们从一开始就为给定功能选择了错误的方式,那么以后将很难更改,因为它将在很多地方使用。

还有一些库使用与 curried 和 uncurried 相似的名称,但我不喜欢这个想法,因为它类似于复制。

谢谢

【问题讨论】:

    标签: ramda.js


    【解决方案1】:

    这里的大多数 Ramda 函数都类似于 reduce。它们以这样的方式进行咖喱,例如,fn(a)(b)(c)fn(a, b)(c)fn(a)(b, c)fn(a, b, c) 都返回相同的值。一小部分 Ramda 函数是不同的。

    这通常是因为 Ramda 对可变参数函数的处理(即那些接受不同数量参数的函数)。 Ramda 不喜欢暴露可变参数函数。 (由于历史原因,pipecompose 及其亲属仍然是可变参数,但其他的并不多。)但是 Ramda 经常使用用户提供的可变参数函数。提供给anyPassallPass 的函数不必是一元的。这里我们将二进制函数传递给anyPass

    const sameParity = (a, b) => a % 2 == b % 2
    
    const foobar = R.anyPass ([gt, sameParity])
    
    foobar (10, 8)  //=> true
    foobar (10, 14) //=> true
    foobar (5, 7)   //=> true
    foobar (5, 14)  //=> false
    foobar (5, 8)   //=> false
    

    我们可以传递三元甚至更高元的函数。

    但是我们如何期望将参数直接传递给这些函数呢?我们可以将anyPass([isSpade, isClub], {rank: 'K', suit: '♣'}). But would we also writeanyPass([gt, sameParity], 10, 8)? If so, the input toanyPass` 写成“一个函数数组,后跟任意数量的其他参数”——几乎不是一个规范的函数。

    或者,我们可以重组anyPass,使其接受一个函数数组,后跟一个参数数组。这听起来不错,直到您意识到这可能是多么不符合人体工程学:您必须调用isBlackCard([myCard]),而不是isBlackCard(myCard)。感觉真的不对。

    因此,对于这几个函数,有一个折衷方案:它们只返回一个函数,从不尝试将其应用于您的值。


    你问这个:

    如果我按照前面的例子,为什么reduce和anyPass不一样,像这样:

    const adder = R.reduce(R.add, 0);
    const sum = adder([1, 2, 3, 4]); //10
    

    嗯,其实就是这样。您可以像大多数 Ramda 函数一样,使用其参数的任何初始子集调用 reduce,然后取回等待其他函数的函数。

    const adder = R.reduce(R.add, 0);
    const sum = adder([1, 2, 3, 4]);
    
    console.log(sum)
    <script src="//cdnjs.cloudflare.com/ajax/libs/ramda/0.26.1/ramda.js"></script>

    唯一真正的区别是您可以将其称为reduce(add, 0, [1, 2, 3, 4])

    但是如果你想要一致性,除了 Ramda 中的几个实际可变参数函数之外,你可以用这种风格调用所有这些函数,而不会损失功能:

    reduce (add) (0) ([1, 2, 3, 4])
    anyPass ([isClub, isSpade]) (myCard)
    

    如今,逐一传递参数实际上已成为我的首选风格。

    【讨论】:

      【解决方案2】:

      在 ramda 中 每个函数都是默认柯里化的

      Ramda 函数是自动柯里化的。这使您可以通过不提供最终参数轻松地从旧函数构建新函数。

      您可以在此处查看文档:https://ramdajs.com/

      这基本上意味着如果一个函数的元数为 3:

      const foo = R.curry((a, b, c) => a + b + c);
      

      在提供所有 3 个参数之前,将返回一个新函数。

      foo(1) // => foo(1, b, c)
      foo(1, 2) => // foo(1, 2, c)
      foo(1)(2)(3) // => 6
      

      当所有参数最终都通过时:

      foo(1, 2, 3) // => 6
      

      【讨论】:

        猜你喜欢
        • 2015-10-04
        • 1970-01-01
        • 2021-02-22
        • 1970-01-01
        • 1970-01-01
        • 2017-04-18
        • 2016-04-22
        • 2010-09-17
        • 1970-01-01
        相关资源
        最近更新 更多