Search code examples
javascriptfunctional-programmingmonadslifting

How to implement a generic lift function for monads?


I have a bunch of arity aware lift functions:

const chain = f => xs =>
  xs.reduce((acc, x) => acc.concat(f(x)), []);

const of = x => [x];

const add = (x, y) => x + y;

const liftM2 = (chain, of) => f => m1 => m2 =>
  chain(x => chain(y => of(f(x, y))) (m2)) (m1);

console.log(liftM2(chain, of) (add) ([2]) ([3])); // [5]

Is it possible to implement a corresponding generic lift function?

const liftM = (chain, of) => f => (...ms) => ...

I guess it is a recursive algorithm, but I cannot wrap my head around it.


Solution

  • Yes, you can do it recursively over ms, but I guess a fold is more suited:

    const lift = (chain, of) => f => (...ms) =>
      ms.reduceRight((acc, m) =>
        (...xs) => chain(x => acc(...xs, x))(m)
      , (...xs) => of(f(...xs))
      )()