1

我正在关注一篇关于JavaScript 中的 Transducers的文章,特别是我定义了以下函数

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);

整个剧本在线

我不明白为什么我不能将最后一个函数 ( 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)

4

3 回答 3

3

最后我找到了一种方法来实现似乎工作正常的组合

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);

完整脚本在线

于 2017-05-17T15:26:00.083 回答
0

more仅使用 2 个功能进行操作。问题是在这里more(squares,divtwo)(sumOf)你执行一个函数,在这里more(squares,divtwo, sumOf)你返回一个需要另一个调用的函数(例如const f = more(squares,divtwo, sumOf); f(args))。

为了拥有可变数量的可组合函数,您可以more为函数组合定义不同的组合。组合任意数量的函数的常规方式是composepipe函数(区别在于参数顺序:pipe按照执行顺序从左到右获取函数,compose相反)。

定义pipeor的常规方式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);

于 2017-05-17T11:12:45.917 回答
0

我仍然无法compose(divtwo,squares)(sumOf)替换compose(divtwo,squares,sumOf)

是的,它们不相等。而且你不应该尝试!注意divtwoandsquares传感器,whilesumOf减速器。他们有不同的类型。不要构建more将它们混合在一起的功能。

如果您坚持使用动态数量的传感器,请将它们放在一个数组中:

[divtwo, squares].reduceRight((t, r) => t(r), sumOf)
于 2017-05-17T23:45:38.747 回答