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.

Sentry image

See why 4M developers consider Sentry, “not bad.”

Fixing code doesn’t have to be the worst part of your day. Learn how Sentry can help.

Learn more

Top comments (0)

👋 Kindness is contagious

Please leave a ❤️ or a friendly comment on this post if you found it helpful!

Okay