Ramda 中的 curry 和偏函数有什么区别?

What is the different between curry and partial function in Ramda?

curry and partial 函数似乎做同样的事情。 (也许唯一的区别是参数的数量)

这只是方便的问题,还是有充分的理由让两个函数做类似的事情。

正如您简要提到的,curry 函数可以接受一个带有 n 个参数的函数,return n 个带有一个参数的函数。柯里化是将函数组合成高阶函数的重要工具。

函数的部分应用是柯里化的一种。事实上,如果你查看 Ramda source code,你会发现 partial 函数是使用 curry 函数实现的。

var _arity = require('./_arity');
var _curry2 = require('./_curry2');


module.exports = function _createPartialApplicator(concat) {
  return _curry2(function(fn, args) {
    return _arity(Math.max(0, fn.length - args.length), function() {
      return fn.apply(this, concat(args, arguments));
    });
  });
};

此外,请查看 this question 从根本上解释差异。

来自更广泛的 FP 社区的许多答案可能会误导您。 Ramda 的柯里化在我看来似乎将 ML 风格语言的柯里化精神带入 Javascript,但并不完全相同。

部分应用程序在 Ramda 中可能是相当标准的。 (免责声明:我是 Ramda 的作者之一。)它也更容易描述。 Ramda 的 partial 函数接受一个 n 个参数的函数和一个 k 个参数的列表(对于某些 0 < k < n),return 是一个 [=16] 的新函数=] 将使用您的新参数和原始参数调用原始函数的参数:

const f = (a, b, c, d, e) => a + b + c + d + e;
// f :: a -> b -> c -> d -> e -> a + b + c + d + e

const g = partial(f, [1, 2]);
g.length; //=> 3
g(3, 4, 5); //=> 15
g(3); //=> NaN ≍ 1 + 2 + 3 + undefined + undefined)
// g :: (c, d, e) -> 1 + 2 + c + d + e

函数returned只是剩余参数的简单函数。如果你调用它的次数太少,它就会像你调用原始函数的次数也太少一样。

柯里化是一个稍微不同的故事。在 many languages 中,curry 函数会将 n 参数的函数转换为嵌套的 1 参数函数序列,因此 (a, b, c) => f(a, b, c) 转换为 a => (b => (c => f(a, b, c)),可以毫无混淆地写成 a => b => c => f(a, b, c)。在 Ramda 中,我们更灵活一些,允许您在一次调用中提供尽可能多的参数,每次 returning 一个函数,直到您提供了足够的总参数来满足原始函数,在这一点上我们称它为 return 那个值。用例子解释可能更容易:

const f = (a, b, c, d, e) => a + b + c + d + e;
// f :: a -> b -> c -> d -> e -> a + b + c + d + e

const h5 = curry(f);
h5.length; //=> 5

const h3 = h5(1, 2);
h3.length; //=> 3
h3(3, 4, 5); //=> 15

const h2a = h3(3);
h2a.length; //=> 2
h2a(4, 5); //=> 15

const h2b = h5(1, 2, 3);
h2b.length; //=> 2
h2b(4, 5); //=> 15

const h2c = h5(1)(2, 3);
h2c.length; //=> 2
h2c(4, 5); //=> 15

const h2d = h5(1)(2)(3);
h2d.length; //=> 2
h2d(4, 5); //=> 15

const h1a = h3(3, 4);
h1a.length; //=> 1
h1a(5); //=> 15

const h1b = h2a(4);
h1b.length; //=> 1
h1b(5); //=> 15

// h5 :: (a, b, c, d, e) -> a + b + c + d + e
//    :: (a, b, c, d) -> e -> a + b + c + d + e
//    :: (a, b, c) -> (d, e) -> a + b + c + d + e
//    :: (a, b, c) -> d -> e -> a + b + c + d + e
//    :: (a, b) -> (c, d, e) -> a + b + c + d + e
//    :: (a, b) -> (c, d) -> e -> a + b + c + d + e
//    :: (a, b) -> c -> (d, e) -> a + b + c + d + e
//    :: (a, b) -> c -> d -> e -> a + b + c + d + e
//    :: a -> (b, c, d, e) -> a + b + c + d + e
//    :: a -> (b, c, d) -> e -> a + b + c + d + e
//    :: a -> (b, c) -> (d, e) -> a + b + c + d + e
//    :: a -> (b, c) -> d -> e -> a + b + c + d + e
//    :: a -> b -> (c, d, e) -> a + b + c + d + e
//    :: a -> b -> (c, d) -> e -> a + b + c + d + e
//    :: a -> b -> c -> (d, e) -> a + b + c + d + e
//    :: a -> b -> c -> d -> e -> a + b + c + d + e

因为 curry 更加灵活,我自己很少使用 partial。但是有些人,咳咳,偏向