function composition with rest operator, reducer and mapper

瘦欲@ 提交于 2019-12-11 07:09:12

问题


I'm following an article about Transducers in JavaScript, and in particular I have defined the following functions

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

Now I want to define a composition operator

const more = (f, g) => (...args) => f(g(...args));

and I see that it is working in the following cases

res2 = reduceWith(more(squares,divtwo)(sumOf), 0, one2ten);
res3 = reduceWith(more(divtwo,squares)(sumOf), 0, one2ten);

which are equivalent to

res2 = reduceWith(squares(divtwo(sumOf)), 0, one2ten);
res3 = reduceWith(divtwo(squares(sumOf)), 0, one2ten);

The whole script is online.

I don't understand why I can't concatenate also the last function (sumOf) with the composition operator (more). Ideally I'd like to write

res2 = reduceWith(more(squares,divtwo,sumOf), 0, one2ten);
res3 = reduceWith(more(divtwo,squares,sumOf), 0, one2ten);

but it doesn't work.

Edit

It is clear that my initial attempt was wrong, but even if I define the composition as

const compose = (...fns) => x => fns.reduceRight((v, fn) => fn(v), x);

I still can't replace compose(divtwo,squares)(sumOf) with compose(divtwo,squares,sumOf)


回答1:


Finally I've found a way to implement the composition that seems to work fine

const more = (f, ...g) => {
  if (g.length === 0) return f;
  if (g.length === 1) return f(g[0]);
  return f(more(...g));
}

Better solution

Here it is another solution with a reducer and no recursion

const compose = (...fns) => (...x) => fns.reduceRight((v, fn) => fn(v), ...x);
const more = (...args) => compose(...args)();

usage:

res2 = reduceWith(more(squares,divtwo,sumOf), 0, one2ten);
res3 = reduceWith(more(divtwo,squares,sumOf), 0, one2ten);

full script online




回答2:


Your more operates with only 2 functions. And the problem is here more(squares,divtwo)(sumOf) you execute a function, and here more(squares,divtwo, sumOf) you return a function which expects another call (fo example const f = more(squares,divtwo, sumOf); f(args)).

In order to have a variable number of composable functions you can define a different more for functions composition. Regular way of composing any number of functions is compose or pipe functions (the difference is arguments order: pipe takes functions left-to-right in execution order, compose - the opposite).

Regular way of defining pipe or compose:

const pipe = (...fns) => x => fns.reduce((v, fn) => fn(v), x);

const compose = (...fns) => x => fns.reduceRight((v, fn) => fn(v), x);

You can change x to (...args) to match your more definition.

Now you can execute any number of functions one by one:

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



回答3:


I still can't replace compose(divtwo,squares)(sumOf) with compose(divtwo,squares,sumOf)

Yes, they are not equivalent. And you shouldn't try anyway! Notice that divtwo and squares are transducers, while sumOf is a reducer. They have different types. Don't build a more function that mixes them up.

If you insist on using a dynamic number of transducers, put them in an array:

[divtwo, squares].reduceRight((t, r) => t(r), sumOf)


来源:https://stackoverflow.com/questions/44022945/function-composition-with-rest-operator-reducer-and-mapper

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!