首页 > 解决方案 > compose 函数如何处理多个参数?

问题描述

这是我需要改进的“撰写”功能:

const compose = (fns) => (...args) => fns.reduceRight((args, fn) => [fn(...args)], args)[0];

这是一个实际的实现:

const compose = (fns) => (...args) => fns.reduceRight((args, fn) => [fn(...args)], args)[0];

const fn = compose([
  (x) => x - 8,
  (x) => x ** 2,
  (x, y) => (y > 0 ? x + 3 : x - 3),
]);

console.log(fn("3", 1)); // 1081
console.log(fn("3", -1)); // -8

这是我的导师提出的改进。

const compose = (fns) => (arg, ...restArgs) => fns.reduceRight((acc, func) => func(acc, ...restArgs), arg);

如果我们在第一次迭代中传递像 func(x, [y]) 这样的参数列表,我仍然不明白我们如何使函数与 [y] 的解压缩数组一起工作?

标签: javascriptfunctional-programmingcompositioncurryingpartial-application

解决方案


让我们分析一下改进后的compose作用

compose = (fns) =>
          (arg, ...restArgs) =>
          fns.reduceRight((acc, func) => func(acc, ...restArgs), arg);

当您compose输入许多功能时,您会返回……一个功能。在你的情况下,你给它一个名字,fn.

这个fn功能是什么样的?通过简单的替换,您可以将其视为:

(arg, ...restArgs) => fns.reduceRight((acc, func) => func(acc, ...restArgs), arg);

哪里fns === [(x) => x - 8, (x) => x ** 2, (x, y) => (y > 0 ? x + 3 : x - 3)]

因此,您可以为这个函数fn提供一些参数,这些参数将与 ; 进行“模式匹配” (arg, ...restArgs)。在您的示例中,当您调用fn("3", 1), argis"3"restArgsis时[1](因此...restArgs扩展到1逗号之后,因此您会看到fn("3", 1)减少为

fns.reduceRight((acc, func) => func(acc, 1), "3");

从这里你可以看到

  1. 最右边的函数,(x, y) => (y > 0 ? x + 3 : x - 3)用两个参数"3"(的初始值acc)和调用1
  2. 结果将通过以下调用作为第一个参数传递给中间函数func
  3. 等等,

但关键是 的第二个参数func,即1,只被最右边的函数使用,而它被传递给其他两个函数但被忽略了!

结论

函数组合是一元函数之间的事情。将它与具有高于 1 的元数的函数一起使用会导致混淆。

例如考虑这两个函数

square = (x) => x**2;   // unary
plus = (x,y) => x + y;  // binary

你能谱写它们吗?好吧,您可以将它们组合成这样的函数

sum_and_square = (x,y) => square(plus(x,y));

compose您在问题底部获得的功能会很顺利:

sum_and_square = compose([square, plus]);

但是,如果您的两个功能是这些呢?

apply_twice = (f) => ((x) => f(f(x))); // still unary, technically
plus = (x,y) => x + y;                 // still binary

你的compose行不通。

即使,如果函数plus被柯里化,例如,如果它被定义为

plus = (x) => (y) => x + y

然后可以考虑将它们组合成一个函数,如下所示:

f = (x,y) => apply_twice(plus(x))(y)

这可以预见地产生f(3,4) === 10.

你可以得到它作为f = compose([apply_twice, plus]).

美容改善

此外,我建议进行“化妆品”更改: make composeaccept...fns而不是fns,

compose = (...fns)/* I've only added the three dots on this line */ =>
          (arg, ...restArgs) =>
          fns.reduceRight((acc, func) => func(acc, ...restArgs), arg);

并且您将能够在没有 groupint 的情况下调用它来将要组合在数组中的函数,例如,您将编写compose(apply_twice, plus)而不是compose([apply_twice, plus]).

顺便说一句,有lodash

该库中有两个函数可以处理函数组合:


推荐阅读