compose 函数如何处理多个参数?
Posted
技术标签:
【中文标题】compose 函数如何处理多个参数?【英文标题】:How does compose function work with multiple parameters? 【发布时间】:2021-11-16 16:19:32 【问题描述】:这是我需要改进的“撰写”功能:
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] 的解压缩数组一起工作?
【问题讨论】:
【参考方案1】:我们来分析一下改进后的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 的函数一起使用会导致混淆。
例如考虑这两个函数
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
,在lodash/fp
中别名为_.compose
【讨论】:
感谢您的回答。我不太明白的一件事是“...restArgs 如何在逗号后扩展为 1”?第二个值是如何从数组中解压出来的? 我不是专家,但关键是如果一个函数有一个参数写成...restArgs
,那么对应的参数 restArgs
将是所有这些参数的数组;当您在函数体中写入...restArgs
时,您将该数组扩展为一个逗号分隔的东西。要查看差异,请在提示符处输入 ((...x) => [...x, x])(1,2,3)
并检查结果。以上是关于compose 函数如何处理多个参数?的主要内容,如果未能解决你的问题,请参考以下文章
Jetpack Compose 和 Compose Navigation 如何处理 Android 活动?
django-rest-framework 如何处理多个 URL 参数?