compose 函数如何处理多个参数?
How does compose function work with multiple parameters?
这是我需要改进的 '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] 数组?
让我们分析一下改进后的 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)
时,arg
是 "3"
并且 restArgs
是 [1]
(因此 ...restArgs
扩展为 1
在逗号之后,所以你会看到 fn("3", 1)
减少到
fns.reduceRight((acc, func) => func(acc, 1), "3");
由此可见
- 最右边的函数,
(x, y) => (y > 0 ? x + 3 : x - 3)
用两个参数"3"
(acc
的初始值)和1
、 调用
- 结果将作为第一个参数传递给中间函数,随后调用
func
、
- 等等,
但重点是 func
的第二个参数,即 1
,仅由最右边的函数使用,而它被传递给 但被忽略 由其他两个函数!
结论
函数组合是一元函数之间的东西。将它与具有高于 1 arity 的函数一起使用会导致混淆。
例如考虑这两个函数
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])
。
外观改进
此外,我建议进行“修饰”更改:让 compose
接受 ...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
该库中有两个函数可以处理函数组合:
_.flow
_.flowRight
, which is aliased to _.compose
in lodash/fp
这是我需要改进的 '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] 数组?
让我们分析一下改进后的 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)
时,arg
是 "3"
并且 restArgs
是 [1]
(因此 ...restArgs
扩展为 1
在逗号之后,所以你会看到 fn("3", 1)
减少到
fns.reduceRight((acc, func) => func(acc, 1), "3");
由此可见
- 最右边的函数,
(x, y) => (y > 0 ? x + 3 : x - 3)
用两个参数"3"
(acc
的初始值)和1
、 调用
- 结果将作为第一个参数传递给中间函数,随后调用
func
、 - 等等,
但重点是 func
的第二个参数,即 1
,仅由最右边的函数使用,而它被传递给 但被忽略 由其他两个函数!
结论
函数组合是一元函数之间的东西。将它与具有高于 1 arity 的函数一起使用会导致混淆。
例如考虑这两个函数
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])
。
外观改进
此外,我建议进行“修饰”更改:让 compose
接受 ...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
该库中有两个函数可以处理函数组合:
_.flow
_.flowRight
, which is aliased to_.compose
inlodash/fp