Monad syntax for JavaScript

Following on from my introduction to monads in JavaScript, and before I get into how they apply to asynchronous programming, I’d like to take a quick detour to improve the usability of the tools we’ve built up. Recall we have a function for composing functions:

var compose = function(f, g) {
  return function(x) { return f(g(x)) };
};

We have some ‘debuggable’ functions:

// sine :: Number -> (Number,String)
var sine = function(x) {
  return [Math.sin(x), 'sine was called.'];
};

// cube :: Number -> (Number,String)
var cube = function(x) {
  return [x * x * x, 'cube was called.'];
};

And finally we have the unit and bind functions for the ‘debuggable’ monad:

// unit :: Number -> (Number,String)
var unit = function(x) { return [x, ''] };

// bind :: (Number -> (Number,String)) -> ((Number,String) -> (Number,String))
var bind = function(f) {
  return function(tuple) {
    var x  = tuple[0],
        s  = tuple[1],
        fx = f(x),
        y  = fx[0],
        t  = fx[1];

    return [y, s + t];
  };
};

These let us compose our debuggable functions to create new debuggable functions:

var f = compose(bind(sine), bind(cube));
f(unit(3)) // -> [0.956, 'cube was called.sine was called.']

This is all well and good, but we should really be able to compute sin(x^3) as a one-liner. With the code we have, this expression would be:

bind(sine)(bind(cube)(unit(3)))

This is hardly convenient, especially when I tell you that the equivalent Haskell expression is:

return 3 >>= cube >>= sine

This reads like a pipeline: take 3, pass it through cube, then pass the result of that through sine. In Haskell, unit is called return, and bind is actually an operator (or infix function) called >>=. The operator >>= doesn’t just convert functions into composable form, it takes a monadic value – in our example, a (Number,String) tuple – and a debuggable function, and deals with unpacking the value from the monad, applying the function to it, and combining the result with the monad in a meaningful way.

Using our existing names, a direct translation to JavaScript of this would be:

bind( bind( unit(3), cube), sine)

Where the bind function now looks like this:

// bind :: (Number,String) -> (Number -> (Number,String)) -> (Number,String)
var bind = function(x, f) {   //  e.g. x = [3, ''], f = cube
  var y  = x[0],              //           3
      s  = x[1],              //           ''
      fy = f(y),              // cube(3) = [27, 'cube was called.']
      z  = fy[0],             //           27
      t  = fy[1];             //           'cube was called.'
  
  return [z, s + t];
};

This representation is clearer, but not quite as expressive as the Haskell version. Let’s go one step forward:

var y = pipe(unit(3), [cube, sine])

This seems reasonably close to Haskell’s version, and to go any further we’d really need some syntactic abstractions that JavaScript does not have. This pipe function is straightforward to implement: it takes a monadic value, and uses bind to pipe it through the list of debuggable functions:

// pipe :: (Number,String) -> [Number -> (Number,String)] -> (Number,String)
var pipe = function(x, functions) {
  for (var i = 0, n = functions.length; i < n; i++) {
    x = bind(x, functions[i]);
  }
  return x;
};

We can easily use this with anonymous inline functions without losing much expressiveness:

var z = pipe(unit(7), [ function(x) { return [x+1, 'inc.'] },
                        function(x) { return [2*x, 'double.'] },
                        function(x) { return [x-1, 'dec.'] }
                      ])

// z == [15, 'inc.double.dec.']

Here we’ve calculated (2 * (7 + 1)) -- 1 using fairly direct syntax, where the operations and the log messages are nicely separated. If you’ve done a lot of asynchronous programming, this will probably be starting to look somewhat familiar, and indeed I’ll be showing where this leads in the next article.