DEV Community

Iven Marquardt
Iven Marquardt

Posted on

Abstracting From Nested Monadic Computations w/o Do-Notation

As soon as we work with monads in Javascript we wind up with nested monadic computations, because there is no do-notation as in Haskell or multi-prompt coroutines as in Kotlin. We cannot use generators either, because they are insufficient for the job.

So are we stuck with nested monadic computations in an ad-hoc fashion like the following?

// Monad

const arrChain = mx => fm =>
  arrFold(acc => x =>
    arrAppend(acc) (fm(x))) ([]) (mx);

// auxiliary function

const arrFold = f => init => xs => {
  let acc = init;

  for (let i = 0; i < xs.length; i++)
    acc = f(acc) (xs[i], i);

  return acc;
};

const arrAppend = xs => ys =>
  xs.concat(ys);

// MAIN

const main = arrChain([1,2]) (x => // nested monadic computation
  arrChain([3,4]) (y =>
    arrChain([5,6]) (z =>
      x === 1
        ? []
        : [x, y, z])));

main; // [2,3,5,2,3,6,2,4,5,2,4,6]
Enter fullscreen mode Exit fullscreen mode

Actually, there is a small improvement. We can treat monadic actions like applicative functors by wrapping them in the context of their corresponding monad:

// Monad

const chain3 = chain => tx => ty => tz => fm =>
  chain(chain(chain(tx) (x => fm(x)))
    (gm => chain(ty) (y => gm(y))))
      (hm => chain(tz) (z => hm(z)));

// MAIN

const main = chain3(arrChain) // much more readable
  ([1,2])
  ([3,4])
  ([5,6])
    (x => x === 1
      ? []
      : [y => [z => [x, y, z]]]);

main; // [2,3,5,2,3,6,2,4,5,2,4,6]
Enter fullscreen mode Exit fullscreen mode

run code

Given chain3 we can implement other arity aware combinators and overload them inside a variadic chainn to gain more flexibility.

More on this and other FP topics in my course for FP in JS:
A fool's scriptum on functional programming.

Discussion (0)