Chainable monads in JavaScript

Gist: the chainable monads presented here are JavaScript functions that allow idiomatic expressions such as

monad1.bind(function1)     ———>     monad2

Since JavaScript is typeless, there’s not really any reason to talk about monad[A] rather than monad[B], but the raison d’être of monads remains. JavaScript monads are created and manipulated by running  convenient functions. The first monad in the chain usually comes from the run of a ‘unit’ function. This article shows all this in the case of the clueless Maybe monad. For more professionally relevant talk, you may want to go asap to the next article.

After acquiring some proficiency in functional programming using JavaScript, I’ve come back lately to an old interest of mine: monads. For those who happen to read here and to share my basic dilemma: “what the hell do we need monads for, as productive professional programmers?” I’d like to anticipate that yes! I have eventually found one single application very, very likely to solve a serious, tough problem of mine at work. But it is pretty complicated and involves the state monad. More details are given in the next article.

This article is not meant as an introduction to monads. It is just a presentation of one possible way to express them using advanced JavaScript concepts. I will suppose that things like map, flatMap (aka bind) and unit are already known and clear to you. Otherwise, the best introduction to monads I can suggest is “Monads are Elephants”, part 1 and 2. Understanding the relationship between flatMap and for-comprehensions and being able to juggle functions between those two representations is imho necessary to obtain anything useful from monads.

Going back to JavaScript: even though monads are mostly seen as typed objects, they don’t have to be. Whilst in Scala we have to make sure we use a f : String -> Monad[Boolean] as argument for the bind method of a Monad[String], in JavaScript we may forget about this, accept the risks of typelessness and enjoy a much readable, expressive syntax.

I found a pair of good, useful pages around showing examples of monads in JavaScript ([1][2]). The basic criterion I have used to pick my favorite ones is that they present code which creates monads as result of the plain execution of named functions, avoiding “new”, prototypes and other pseudo class-like JS muck.

Another thing the pages I’ve mentioned here have in common (but which instead I find a lesser idea) is that they express the various unit, map, flatMap/bind etc. as binary factory methods operating on pairs of monads and mapping functions which are given as parameters to the factory; for example:

bind(monad,flatmappingFunction);

Alas, this becomes pretty nested, convoluted and difficult to read as soon as you begin to bind more than a pair of monads to each other. That’s why I prefer to see monads as entities with own capabilities, so that I may write:

monad.bind(functionA).bind(functionB).bind(functionC)

knowing that monad.bind(functionA) will create a new monad instance with its own bind method, ready to accept functionB as its parameter and build a third monad instance, and so on.

Let’s stress once more that in this schema monads are always the product of the execution of plain named functions. There is no “new” involved nor prototypes to inherit from; “this” is mostly the running function (and when not, it’s always under the strict supervision of apply :-)). The only objects in the game are JS literals returned at the end of the various runs.

Also relevant to observe here is that my schema uses the module pattern([3]). The named function returns an object, which I call Monad.maybe or Monad.state to avoid littering the global object (caveat: I haven’t checked whether Monad namespaces exist already in any browser and what are their attributes!), and exposes the whole palette of methods for the given monad. So there is indeed a factory, but you only need Monad.<xxxx>.unit to start the dances.

All the code shown here is available at the Github repository named geiesmonads (user Muzietto). The next part of this article is dedicated to the Maybe monad (aka Option), which I personally find unfit for any practical usage in our day jobs (ok, ok: no more “if null”, big deal!). I am presenting it here only to illustrate the concept of chained JavaScript monads with a truly simple example. The real thing I am pursuing is the State monad, with its I/O management facets. But that’s a harder nut to crack and comes only in the next article, where you may want to jump right now, if you are already acquainted with Maybes and are looking for something really professionally relevant.

Chainable Maybe monad in JavaScript

So, here is my instanceable/chainable Maybe monad. Again, the only producer of monads (here and in other types of monad that I will present later) is unit. Producing a monad means attaching the various map/flatMap/unit/flatten/bind methods to the result function/object/monad/youNameIt that will be returned by unit. I’ve managed to have bind delegate to unit the preparation of the monad result of its binding. So, the monad builder is always unit.

You may want to compare this implementation to the Maybe monad from [2].

var myMaybeMonad = function() {
var unit = function(value){
var result = function(optionalBindingFunction){
if (optionalBindingFunction) { // synt sugar
return bind.apply(result,[optionalBindingFunction]);
}
else {
return value;
}
};
result.bind = bind;
result.flatten = flatten;
result.unit = unit;
result.instanceOf = instanceOf;
result.map = map;
return result;
};

var map = function(fab){return bind(lift(fab));};

// to be used in the context of the monad
var flatten = function(){
if (this()) {return this();}
else { // a None is an empty function
return function(){};
}
};

// famb(flatten(ma)) –> mb
var bind = function(famb){
// runs in the context of the monad…
return unit(famb(flatten.apply(this)))();
};

var instanceOf = function(){
return ‘maybe’;
};

// fab –> famb
var lift = function(fab){
return function(x) {
return unit(fab(x));
};
};

return {
unit: unit,
lift: lift,
map: map,
flatten: flatten,
instanceOf: instanceOf,
bind: bind
};
}();

Monad.maybe = myMaybeMonad;

Monad.maybe.unit deserves a little explanation. It has here two roles:

  1. canonical: factory method for Maybes, given a value to wrap inside
  2. special: syntactic sugar to allow to remove all explicit invocations to bind

The second role makes the two following instructions identical:

monad.bind(functionA).bind(functionA)   and   monad(functionA)(functionB)

Please note the sugary business is realized in the case of this Maybe monad, but not in the State monad presented in next article.

The example usage is taken straight from [2]. We need a sample function that transforms values contained in the maybes, like

var more = function(value){return 'more ' + value;};

First we need to lift it and make it useable by bind/flatMap:

var mMore = Monad.maybe.lift(more);

As you can see in the code of lift, this wraps more into a:

function(x) {return unit(more(x));}

Given a Maybe named coffee and containing, surprisingly, the string “coffee”, we bind it with mMore writing:

coffee.bind(mMore)  or  coffee(mMore)

and we get a Maybe which, once flattened, returns “more coffee”.
mission_accomplished

[1] http://igstan.ro/posts/2011-05-02-understanding-monads-with-javascript.html
[2] http://jabberwocky.eu/2012/11/02/monads-for-dummies/
[3] http://www.yuiblog.com/blog/2007/06/12/module-pattern/

Leave a comment