具有 rest operator、reducer 和 mapper 的函数组合
function composition with rest operator, reducer and mapper
我正在关注一篇关于 Transducers in JavaScript 的文章,特别是我定义了以下函数
const reducer = (acc, val) => acc.concat([val]);
const reduceWith = (reducer, seed, iterable) => {
let accumulation = seed;
for (const value of iterable) {
accumulation = reducer(accumulation, value);
}
return accumulation;
}
const map =
fn =>
reducer =>
(acc, val) => reducer(acc, fn(val));
const sumOf = (acc, val) => acc + val;
const power =
(base, exponent) => Math.pow(base, exponent);
const squares = map(x => power(x, 2));
const one2ten = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
res1 = reduceWith(squares(sumOf), 0, one2ten);
const divtwo = map(x => x / 2);
现在我想定义一个组合运算符
const more = (f, g) => (...args) => f(g(...args));
我发现它在以下情况下有效
res2 = reduceWith(more(squares,divtwo)(sumOf), 0, one2ten);
res3 = reduceWith(more(divtwo,squares)(sumOf), 0, one2ten);
相当于
res2 = reduceWith(squares(divtwo(sumOf)), 0, one2ten);
res3 = reduceWith(divtwo(squares(sumOf)), 0, one2ten);
整个脚本是online.
我不明白为什么我不能将最后一个函数 (sumOf
) 与组合运算符 (more
) 连接起来。理想情况下我想写
res2 = reduceWith(more(squares,divtwo,sumOf), 0, one2ten);
res3 = reduceWith(more(divtwo,squares,sumOf), 0, one2ten);
但是没用。
编辑
很明显,我最初的尝试是错误的,但即使我将构图定义为
const compose = (...fns) => x => fns.reduceRight((v, fn) => fn(v), x);
我还是不能用compose(divtwo,squares,sumOf)
替换compose(divtwo,squares)(sumOf)
您的 more
只有 2 个功能。问题是这里 more(squares,divtwo)(sumOf)
你执行了一个函数,这里 more(squares,divtwo, sumOf)
你 return 一个需要另一个调用的函数(例如 const f = more(squares,divtwo, sumOf); f(args)
)。
为了拥有可变数量的可组合函数,您可以为函数组合定义不同的 more
。组合任意数量函数的常规方法是 compose
或 pipe
函数(不同之处在于参数顺序:pipe
按照从左到右的顺序执行函数,compose
-相反)。
定义pipe
或compose
的常规方式:
const pipe = (...fns) => x => fns.reduce((v, fn) => fn(v), x);
const compose = (...fns) => x => fns.reduceRight((v, fn) => fn(v), x);
您可以将 x
更改为 (...args)
以匹配您的 more
定义。
现在您可以一个接一个地执行任意数量的函数:
const pipe = (...fns) => x => fns.reduce((v, fn) => fn(v), x);
const compose = (...fns) => x => fns.reduceRight((v, fn) => fn(v), x);
const inc = x => x + 1;
const triple = x => x * 3;
const log = x => { console.log(x); return x; } // log x, then return x for further processing
// left to right application
const pipe_ex = pipe(inc, log, triple, log)(10);
// right to left application
const compose_ex = compose(log, inc, log, triple)(10);
最后我找到了一种实现似乎工作正常的组合的方法
const more = (f, ...g) => {
if (g.length === 0) return f;
if (g.length === 1) return f(g[0]);
return f(more(...g));
}
更好的解决方案
这是另一个使用 reducer 且没有递归的解决方案
const compose = (...fns) => (...x) => fns.reduceRight((v, fn) => fn(v), ...x);
const more = (...args) => compose(...args)();
用法:
res2 = reduceWith(more(squares,divtwo,sumOf), 0, one2ten);
res3 = reduceWith(more(divtwo,squares,sumOf), 0, one2ten);
完整脚本online
I still can't replace compose(divtwo,squares)(sumOf)
with compose(divtwo,squares,sumOf)
是的,它们并不等同。无论如何你都不应该尝试!请注意,divtwo
和 squares
是 转换器 ,而 sumOf
是 减速器 。他们有不同的类型。不要构建混淆它们的 more
函数。
如果您坚持使用动态数量的换能器,请将它们放在一个数组中:
[divtwo, squares].reduceRight((t, r) => t(r), sumOf)
我正在关注一篇关于 Transducers in JavaScript 的文章,特别是我定义了以下函数
const reducer = (acc, val) => acc.concat([val]);
const reduceWith = (reducer, seed, iterable) => {
let accumulation = seed;
for (const value of iterable) {
accumulation = reducer(accumulation, value);
}
return accumulation;
}
const map =
fn =>
reducer =>
(acc, val) => reducer(acc, fn(val));
const sumOf = (acc, val) => acc + val;
const power =
(base, exponent) => Math.pow(base, exponent);
const squares = map(x => power(x, 2));
const one2ten = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
res1 = reduceWith(squares(sumOf), 0, one2ten);
const divtwo = map(x => x / 2);
现在我想定义一个组合运算符
const more = (f, g) => (...args) => f(g(...args));
我发现它在以下情况下有效
res2 = reduceWith(more(squares,divtwo)(sumOf), 0, one2ten);
res3 = reduceWith(more(divtwo,squares)(sumOf), 0, one2ten);
相当于
res2 = reduceWith(squares(divtwo(sumOf)), 0, one2ten);
res3 = reduceWith(divtwo(squares(sumOf)), 0, one2ten);
整个脚本是online.
我不明白为什么我不能将最后一个函数 (sumOf
) 与组合运算符 (more
) 连接起来。理想情况下我想写
res2 = reduceWith(more(squares,divtwo,sumOf), 0, one2ten);
res3 = reduceWith(more(divtwo,squares,sumOf), 0, one2ten);
但是没用。
编辑
很明显,我最初的尝试是错误的,但即使我将构图定义为
const compose = (...fns) => x => fns.reduceRight((v, fn) => fn(v), x);
我还是不能用compose(divtwo,squares,sumOf)
compose(divtwo,squares)(sumOf)
您的 more
只有 2 个功能。问题是这里 more(squares,divtwo)(sumOf)
你执行了一个函数,这里 more(squares,divtwo, sumOf)
你 return 一个需要另一个调用的函数(例如 const f = more(squares,divtwo, sumOf); f(args)
)。
为了拥有可变数量的可组合函数,您可以为函数组合定义不同的 more
。组合任意数量函数的常规方法是 compose
或 pipe
函数(不同之处在于参数顺序:pipe
按照从左到右的顺序执行函数,compose
-相反)。
定义pipe
或compose
的常规方式:
const pipe = (...fns) => x => fns.reduce((v, fn) => fn(v), x);
const compose = (...fns) => x => fns.reduceRight((v, fn) => fn(v), x);
您可以将 x
更改为 (...args)
以匹配您的 more
定义。
现在您可以一个接一个地执行任意数量的函数:
const pipe = (...fns) => x => fns.reduce((v, fn) => fn(v), x);
const compose = (...fns) => x => fns.reduceRight((v, fn) => fn(v), x);
const inc = x => x + 1;
const triple = x => x * 3;
const log = x => { console.log(x); return x; } // log x, then return x for further processing
// left to right application
const pipe_ex = pipe(inc, log, triple, log)(10);
// right to left application
const compose_ex = compose(log, inc, log, triple)(10);
最后我找到了一种实现似乎工作正常的组合的方法
const more = (f, ...g) => {
if (g.length === 0) return f;
if (g.length === 1) return f(g[0]);
return f(more(...g));
}
更好的解决方案
这是另一个使用 reducer 且没有递归的解决方案
const compose = (...fns) => (...x) => fns.reduceRight((v, fn) => fn(v), ...x);
const more = (...args) => compose(...args)();
用法:
res2 = reduceWith(more(squares,divtwo,sumOf), 0, one2ten);
res3 = reduceWith(more(divtwo,squares,sumOf), 0, one2ten);
完整脚本online
I still can't replace
compose(divtwo,squares)(sumOf)
withcompose(divtwo,squares,sumOf)
是的,它们并不等同。无论如何你都不应该尝试!请注意,divtwo
和 squares
是 转换器 ,而 sumOf
是 减速器 。他们有不同的类型。不要构建混淆它们的 more
函数。
如果您坚持使用动态数量的换能器,请将它们放在一个数组中:
[divtwo, squares].reduceRight((t, r) => t(r), sumOf)