|
|
1
VLAZ Sohail Arif
4 年前
问题在于
_.flow()
它期望第一个参数之后的所有内容都是一元函数,这样它就可以将结果传递给所有参数。当你想对所有函数应用相同的参数集,只更改第一个参数时,这是一个挑战。有几种方法可以做到这一点。
使用Lodash
你可以利用
_.partialRight
对每个功能进行部分分配。
partialRight
将根据函数接受的参数数量,从右到左应用参数。
const fn = (a, b, c, d) => console.log(a, b, c, d);
// behaves similar to (a, b) => console.log(a, b, "yak", "zebra")
const newFn = _.partialRight(fn, "yak", "zebra");
newFn("alpaca", "beaver");
<script src="https://cdn.jsdelivr.net/npm/lodash@4.17.19/lodash.min.js"></script>
但是,您仍然可以从左向右传递参数,这将把部分应用的参数向右推:
const fn = (a, b, c, d) => console.log(a, b, c, d);
// behaves similar to (a, b) => console.log(a, b, "yak", "zebra")
const newFn = _.partialRight(fn, "yak", "zebra");
newFn("alpaca", "beaver", "cat");
<脚本src=“https://cdn.jsdelivr.net/npm/lodash@4.17.19/lodash.min.js“></script>
假设所有功能都具有
最多
拿
n
我们可以提出的论点数量:
-
获取数组
n
要应用于所有函数的参数。
-
获取所有功能。
-
做
部分权利
除了第一个参数外,所有函数都使用其他参数。自从我们申请
n-1
每个参数的参数,现在所有参数都可以被调用,就像它们是一元的一样。
-
使用
flow
关于step的新功能
3.
-
使用第一个参数启动链。
然后,这将调用所有函数,以便
第一个论点
是
最后结果
第二个及以后的参数将基于初始参数,因此所有函数的参数都是相同的
function nAryFlow(argsArray, ...fns) { //1. and 2. - get arguments and functions
const start = argsArray[0];
const rest = argsArray.slice(1);
const convertedFns = fns.map(f => _.partialRight(f, ...rest)) //3. Turn all functions into unary ones
return _.flow( //4. `flow` through the functions
...convertedFns
)(start); //5. use the initial fist argument to kick things off
}
const fn1 = (who1, who2, who3) => `${who1}, ${who2}, and ${who3} are best friends.`;
const fn2 = (friends, who2, who3) => `${friends} Especially ${who2} and ${who3}.`;
const fn3 = (story, who2) => `${story} They all met at a party thrown by ${who2}`;
const args = ["Alice", "Bob", "Carol"];
const result = nAryFlow(args, fn1, fn2, fn3);
console.log(result)
<脚本src=“https://cdn.jsdelivr.net/npm/lodash@4.17.19/lodash.min.js“></script>
不使用Lodash
以上所有操作都可以在没有Lodash的情况下轻松完成。相反,我们可以使用
Array#reduce
遍历所有函数并应用参数。这一次,我们直接应用它们,而不是预处理函数,但整体操作和效果是相同的:
-
第一个函数接受所有参数。
-
任何进一步的函数都接受最后一个函数和从开始的第二个参数的结果:
function nAryFlow(argsArray, ...fns) {
const start = argsArray[0];
const rest = argsArray.slice(1);
return fns.reduce((last, f) => f(last, ...rest), start);
}
const fn1 = (who1, who2, who3) => `${who1}, ${who2}, and ${who3} are best friends.`;
const fn2 = (friends, who2, who3) => `${friends} Especially ${who2} and ${who3}.`;
const fn3 = (story, who2) => `${story} They all met at a party thrown by ${who2}`;
const args = ["Alice", "Bob", "Carol"];
const result = nAryFlow(args, fn1, fn2, fn3);
console.log(result)
使用更高阶函数的变体
作为一种变体,可以将其拆分为多个高阶函数,这可能会在某些情况下产生更好的语法
nAryFlow(f1, f2, f3, fN)(arg1, arg2, arg3, argN)
:
function nAryFlow(...fns) {
return function (...args) {
const start = args[0];
const rest = args.slice(1);
return fns.reduce((last, f) => f(last, ...rest), start);
}
}
const fn1 = (who1, who2, who3) => `${who1}, ${who2}, and ${who3} are best friends.`;
const fn2 = (friends, who2, who3) => `${friends} Especially ${who2} and ${who3}.`;
const fn3 = (story, who2) => `${story} They all met at a party thrown by ${who2}`;
const chain = nAryFlow(fn1, fn2, fn3);
const result1 = chain("Alice", "Bob", "Carol");
const result2 = chain("Rachel Green", "Monica Geller", "Chandler Bing");
console.log(result1);
console.log(result2);
使用函数
对于这里稍微不同的观点,你可以使用一个代数结构,称为
Functor
以简化语法。关于functor的本质是它们有一个
.map()
接受函数的方法。如果你想起
Array#map
那么你没有错。
基本思想是,functor持有一个值,并允许通过函数对其进行修改
.map()
然后,它可以规定如何将函数应用于其值。结果
.map
始终与已映射的functor类型相同,因此您始终可以继续映射,并确保每次应用程序都是相同的。对于数组,你总是会得到一个长度相同的新数组,其中每个成员都被转换了。其他函数子可以应用给定的函数
.map()
与数组的作用不同,但它始终是一致的。
那么,背景完成后,这个函数子看起来是这样的:
class NAryFlow {
constructor(argsArray) {
this.value = argsArray[0];
this.rest = argsArray.slice(1);
}
static of(argsArray) {
return new NAryFlow(argsArray);
}
map(fn) {
return NAryFlow.of(
[ fn(this.value, ...this.rest), ...this.rest ]
);
}
}
const fn1 = (who1, who2, who3) => `${who1}, ${who2}, and ${who3} are best friends.`;
const fn2 = (friends, who2, who3) => `${friends} Especially ${who2} and ${who3}.`;
const fn3 = (story, who2) => `${story} They all met at a party thrown by ${who2}`;
const result = NAryFlow.of(["Alice", "Bob", "Carol"])
.map(fn1)
.map(fn2)
.map(fn3)
.value;
console.log(result)
与上述两个类似的想法-我们接受参数,并将它们全部应用于我们给出的每个函数
.map()
每次我们打电话
.map()
第一个论点将是最后一个结果。
这里有一个细微的变化,使用
ES6 getters
我认为它的语法稍微好一些,但希望保持之前的实现更简单。
class NAryFlow {
constructor(argsArray) {
this.args = argsArray;
}
static of(argsArray) {
return new NAryFlow(argsArray);
}
map(fn) {
return NAryFlow.of(
[ fn(...this.args), ...this.rest ]
);
}
get value() {
return this.args[0];
}
get rest() {
return this.args.slice(1);
}
}
const fn1 = (who1, who2, who3) => `${who1}, ${who2}, and ${who3} are best friends.`;
const fn2 = (friends, who2, who3) => `${friends} Especially ${who2} and ${who3}.`;
const fn3 = (story, who2) => `${story} They all met at a party thrown by ${who2}`;
const result = NAryFlow.of(["Alice", "Bob", "Carol"])
.map(fn1)
.map(fn2)
.map(fn3)
.value;
console.log(result)
|