Le Sparte
Le Sparte

Reputation: 163

How to create a variadic high-order function reusing the returned result in JS

Consider I have an undetermined number of functions f, each one needing one argument and returning one result. How should I write a function "execute" taking the first argument as the number, and all the other arguments as functions to be applied to the result of each preceding function?

Here's my guess:

let plus1 = d => d += 1;
let plus2 = d => d += 2;
let write = d => document.write(d);


let execute = function(n,...functions){
  functions.forEach((d)=>d(n));
}

execute(4,plus1,plus2,write); 

I'm expecting 7 ((4+1)+2).

Thanks for your help!

Upvotes: 2

Views: 41

Answers (2)

Anler
Anler

Reputation: 1993

The monoidal combination of two functions does exactly what you want: it propagates an argument through all the combined functions, the difference with your example is that all the results are later combined by another monoidal combination:

function monoidCombine(f, g) {
  let ftype = typeof f;
  let gtype = typeof g;
  if (ftype === "function" && gtype === "function") {
    return function(input) {
      return monoidCombine(f(input), g(input));
    };
  }

  if (ftype === "number" && gtype === "number") {
    return f + g;
  }

  throw new Error(`No case for monoidCombine(${ftype}, ${gtype})`);
}

function execute(n, ...functions) {
  return functions.reduce((f, g) => monoidCombine(f, g))(n);
}

execute(1, (x) => x + 3, (x) => x + 1);  
// ^-- is equivalent to ((x) => x + 3)(1) + ((x) => x + 1)(1)
// so the result is 6

Upvotes: 1

Nina Scholz
Nina Scholz

Reputation: 386680

You could use Array#reduce, which returns a result, while using a function with a given value.

let plus1 = d => d + 1,
    plus2 = d => d + 2,
    write = d => console.log(d),
    execute = (n, ...fn) => fn.reduce((n, f) => f(n), n);

execute(4, plus1, plus2, write); 

Shorter version as Yury Tarabanko suggested

let plus1 = d => d + 1,
    plus2 = d => d + 2,
    write = d => console.log(d),
    execute = (...args) => args.reduce((v, f) => f(v));

execute(4, plus1, plus2, write); 

Upvotes: 1

Related Questions