我正在关注有关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)

最佳答案

最后,我找到了一种方法,可以实现看起来不错的合成

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

09-19 14:57