Handling I/O with the state monad in JavaScript

Gist: the state monad allows to chain (i.e. to execute in sequence) a wide sort of operations, each one returning one single parameter called “value”. A second parameter called “state” is passed through the chain of the operations, acting as a representation of the evolving state of the system throughout the various steps. A JS implementation of the state monad is presented here. The state monad appears to be very well capable of handling I/O operations. A simple GUI composed by prompt (returning as value the user input) and alert (returning as value undefined) is put at work with interesting results. All this in the comfort of your favorite browser.

Thinking about the state monad implementations given in [1] and [2] I have come to define a chainable state monad of my own liking. Going through the superb “Monads are Elephants – part 4” ([3]) and looking from a close distance the working of a Scala I/O monad I came to realize that the state monad in my hands should be able to perform those I/O operations as well. For those who are acquainted with the latter post, it will be clear that this  – obviously typeless – monad of mine does not handle the state of the system, let alone the state of the world, with the care deemed necessary by the author of that article.

Once more, the monad I present is based on the command module ([4]). Its code is organized in the following manner:

var myStateMonad = function() {
  var monad, unit, bind, flatten, map, lift, filter,
  fail, executor, onError, instanceOf
  ;
  …
  … code …
  …
  return {
    // static methods
    monad: monad,
    unit: unit,
    lift: lift,
    liftM: lift
  };
}();

Monad.state = myStateMonad;

Likewise the maybe monad of the previous article, it is possibly overkill to export all the methods. Actually I see that so far I’ve been using only monad, unit, filter and onError. The other ones are invoked by the monad itself.

WHAT ABOUT Function.prototype.bind?: The process described in this page produces a monad, a JS function, which has its own prototype.bind method overridden. That’s a bad idea for production code. But I really dislike the name flatMap, so I won’t use it in this experiment.

The most important method in the previous API is monad. And what is that? It’s actually a data constructor.

A state monad is a function

The state monad is basically a function that takes a state and returns a pair (state,value). Using Haskell syntax, its type is:

s -> (s,a)

Once available, a state monad should be callable through a simple invocation monad(state) and yet, almost any language forces to invoke it through an accessor method called runState, s2scp (state to state-content pair) and the likes. This is awkward: this monad is a function, it’s not a “container” like the maybes or the lists. Forcing me to treat it as an ‘object’ is unnatural.

I understand this must be done in Java or Scala, but discovering I have to do it also in Haskell (even though there are a few subtle differences in the matter) was kinda disappointing.

Here JavaScript shines once more. In JavaScript we can build the state monad as a function and pass it a state as its natural only argument.

In JavaScript we can shape the monad as a JS function and decorate that function with bind and the other accessory methods. We don’t even have to attach them to the monad prototype (go ahead if you like, but to me that’s a pointless complication).

That’s the job of the static method Monad.state.monad; this method receives a plain JS function s -> (s,a), which I’ll call fssa, and transforms it in a state monad. Please refer to the geiesmonads_2.0.js file.

var monad = function(fssa) {
  // clone using its prototype.bind
  var result = fssa.bind({});
  result.bind = bind;
  result.flatten = flatten;
  result.map = map;
  result.filter = filter;
  result.iff = iff;
  result.onError = onError;
  result.instanceOf = instanceOf;
  return result;
}

The other building block is unit (aka return); as its nature commands, unit wraps a user value and allows to access that value anytime within the monad context by providing a state.

var unit = function(value) {
  var fssa = function(state) {
    return {state:state, value:value};
  }
  return monad(fssa);
  }

The product of both monad and unit is first and foremost a JS function. A function enriched with methods to allow the chaining of calls.

The most important thing to give the monad is, as usual, bind (aka flatMap). This is how bind is defined inside the module at the top of this post:

var bind = function (famb) { // famb : a -> m b
  var that = this;
  return monad(function(state) {
    // cp = current pair
    var cp = that(state);
    return famb(cp.value)(cp.state);
  });
}

At the heart of the code you may recognize the steps that realize the sequential execution flow of the two bound operations. Those lines will execute when an external state will be applied. We are inside the current monad (let’s call it A) and we refer to it as that because of the famous JS quirk:

  1. A (i.e. the first operation) executes: that(state) returns an object {state:A_STATE,value:A_VALUE} which we name cp (current pair)
  2. the monad B resulting from the binding is the product of the application of the function famb to cp.value; monad B is therefore famb(cp.value)
  3. the state that this monad will have to receive is not the original one provided to A, because A could have modified it!!; the state for B gotta be the one produced by the resolution of A, and that’s cp.state; therefore we use that state to resolve the B monad: famb(cp.value)(cp.state)
  4. this convoluted application of state altogether defines a function s -> (s,b). We gotta return a monad instance and therefore we pass the function to the monad constructor

The rest of this post is dedicated to the presentation of a simple GUI featuring flow control, with the state monad actually acting as I/O monad. A further post presents heavier applications of the state monad.

A very simple GUI: prompt and alert

With the state monad in our hands we can start doing some interesting experiments, still under the guide and inspiration of [3].

First of all, we need one input and one output function:

var getString = function(value) {
  return Monad.state.unit(prompt(value));
};
var putString = function(value) {
  return Monad.state.unit(alert(value));
};

Please note that getString and putString are not state monads. But once they are given a value, we have two simple, nice state monads in our hands to work with.

getString and putString are actually what I called famb while explaining bind. Why famb? Because it’s a shortcut for function from a to monad b. Famb’s are the standard argument for bind. In the present situation, these two functions take a value and wrap it with a plain state monad.

getString needs to be told (possibly from a preceding monad or directly from the programmer) what value to show in the prompt popup. The value getString passes down the chain is instead the return value of prompt(), i.e. the string containing the user input.

putString needs to be told (possibly from a preceding getString or directly from the programmer) what value to show in the alert popup. The value putString passes down the chain is instead the return value of alert(), i.e. undefined. No big deal.

Wrapping prompt and alert with unit will entail that no actions are performed by these monads to the input state (check the code of unit about this point). It doesn’t have to be this way; we could do something to the state, but we don’t have to. Actually, here what we really care about are the side effects of these calls: we need the popups to interact with the user!

If JavaScript were Scala, we would put our two monads at work in a for-comprehension like:

for {
  name <- getString('what is your name?');
  x <- putString('welcome ' + name); // we know x will be undefined, so what?
} yield …  // whatever gets yielded, we don’t care…

…and it would be (almost) crystal clear what we want our little program to do. But for-comps in JS aren’t available so we must perform one further step. We do this keeping in mind the relationship between for-comps, map and bind (aka flatMap) [4].

The previous for-comprehension becomes:

getString('what is your name?')
  .flatMap(name -> putString('welcome ' + name) // flatMap === bind
  .map(x -> WHATEVER)
)

In other words, if we want to chain putString after the state monad getString('what is your name?'), we must wrap it with a lambda(value) in order to make it palatable to bind. The result is then:

var promptThenGreet = getString('what is your name?')})
  .bind(function(name){ return putString('welcome ' + name);});

promptThenGreet(0); // whatever state

This produces two popups in sequence. The name you insert in the first comes back welcomed in the second popup.

promptThenGreet

A LITTLE CAVEAT: whatch out for getString: since we need its value first thing to feed it to unit, it fires the popup immediately at the moment of definition of the monad promptThenGreet, without waiting for the state to be provided at runtime (that’s to say at the following line). Because the other operations in the chain wait patiently their turn and fire only once the state is provided, the workaround is to put in front of the first getString a dumb fixed-point state monad which I called start.

var start = Monad.state.monad(function(state) {
  return {state : state, value : 'whatever'};
});

var promptThenGreet2 = start
  .bind(function(_) { return getString('what is your name?'); })
  .bind(function(name) { return putString('welcome ' + name); });

promptThenGreet2(0); // whatever state

This guarantees that the first popup will appear only during the run with the state.

So far, this state monad has done nothing with state

I reckon what I have shown here is just a couple of examples of an I/O monad. There is not really an evolving state in these examples. Those examples are provided in a following post.

Having said that, we can complete the talk about I/O and show how a state monad can handle errors.

Filtering values and managing the execution flow

Still following the Scala example from [3], we create a filter:

// predicate: value -> boolean
function filter(predicate, msg) {
  function _iff(value) {
    if (predicate(value)) {
      return unit(value);
    } else {
      return fail(msg + '-' + value);
    }
  };
  return this.bind(_iff);
};

Then we create a failing a -> mb function:

function fail(value) {
  return monad(function(state) { throw {message : value}; });
};

Let’s spend one minute here: this code will become part of the public state monad API. This function is gonna become a method attached to the main monad s -> (s,a) function. Therefore, inside filter this is the chainable monad itself.

What is _iff, then? _iff is a function that takes a value and returns:

  • a plain state monad that forwards the value, when the value satisfies the predicate
  • a failing state monad that carries information about the filter failure, when not

Therefore, _iff is an a -> mb function, which may be bound without trouble. By returning this.bind(_iff) from filter we just add one more ring to the chain and get ready to go on.

If _iff says yes and returns unit(value), when we run the monad the ring will pass the state on. Problem is: if _iff returns fail('msg - boom!') instead, we’ve put inside our chain a ring that will explode no matter what.

In other words:

getString(‘who are you?’)
  .filter(function(name) {
    return (name != ‘Jeremy’);
  }, ’Not welcome’);

is the monad resulting by binding the outcome of the run of the filter predicate to the initial getString monad. That’s a state monad that will throw an exception whenever any clueless Jeremy provides his name at the prompt. Hmmm, isn’t this too extreme? We may use an onError handling monad:

function onError(errorHandler) {
  var that = this;
  return function(state) {
    try {
      return that(state);
    } catch (exception) {
      return errorHandler(exception)(state);
    }
  };
};

Binding all this somewhere down the chain will guarantee that, wherever in the previous computation an exception is thrown, the provided errorHandler will take care of the graceful resolution of the problem.

The errorHandler can better be itself a state monad, so to be able to keep chaining behavior afterwards. The handler will handle the exception as its own input value, possibly taking the state (which has been neatly forwarded by onError) into account; in our example the handler ain’t that smart and just alerts Jeremy that he’s not welcome and therefore must go away.

var showTheDoor = function(exc) {
  return putString('go away-' + exc.message);
}

Tying it all together we have:

var promptThenCheckThenGreetOrElseShowTheDoor = start
  .bind(function(_) { return getString('what is your name?\nNB - Jeremy is not welcome'); })
  .filter(function(x) { return (x!='Jeremy'); }, 'not welcome')
  .bind(function(y) { return putString('welcome ' + y); })
  .onError(showTheDoor);

promptThenCheckThenGreetOrElseShowTheDoor(0);

Please note that we don’t need to wrap the whole computation inside a single closure to carry the user-entered value until the end of the flow:

  • if the filter succeeds, the good value will be passed as y to putString
  • if the filter fails, the bad value will reach onError through the throw-catch mechanism

promptThenCheckThenGreetOrElseShowTheDoor

The next flow operator is iff(predicate, trueMonad, falseMonad); it chooses which monad to execute depending on a predicate check.

function iff(predicate, trueMonad, falseMonad) {
  function _iff(value) {
    if (predicate(value)) {
      return trueMonad.bind(function(_){return unit(value)})
    } else {
      return falseMonad.bind(function(_){return unit(value)})
    }
  }
return this.bind(_iff);
}

Why is all this bloody relevant?

What we have here is a very lightweight API (unit, bind, filter, iff, onError) for describing a sequence of operations. The operations can be made complex at will, and they may even involve interactions with the user, the filesystem, an external db or the web.

The state of the execution is kept safely inside the running process, it may be updated at will at each step and the updated value is passed effortlessly to the next step in the execution chain. Like the operations, also the state can be made exceedingly complicated to suit the complexity of the operations. The thread of the operations would act as the controller/presenter/youNameIt, while the state would contain handles to the view.

The complete, final sequence is built from simpler components using a very small set of operations. Component monads can be further composed together, the way showTheDoor took seat inside onError. Probably we would need a couple more of handler monads in our toolbox to make repetitive things simpler (I haven’t yet spoken about map, lift and flatten, but they’re there in the geiesmonads github repository, covered with tests and perfectly working). Then we’d need a GUI that allows drag and drop of the components into the final bound sequence.

If I were to make a bet I’d say that Scratch, the program that teaches programming to kids, must be using some kind of mechanism like this at its heart.

scratch

I can’t yet see with clarity the impact of recursion on all this. At the end of [3] we are warned that running the complete solution proposed there (a real-time continuous gatekeeper routine) causes sooner or later a stack overflow. And in the previous post I put some pointers that show the not quite efficient implementation of closures in JS engines. But ok, I can see anyway a lot of useful non-recursive applications for these concepts.

What I enjoy the most is that I’ve brought all these nice Haskell/OCaml/Scala concoctions into… plain JavaScript, the language that pays my bills at the end of the month. The road ahead is still long, but it looks feasible and promising.

As with OO design patterns (you don’t go to work saying to yourself “today I’m gonna do two Singletons and one AbstractFactory”), I reckon it’s necessary to let the state monad blend naturally and invisibly in the FP landscape; it’s necessary to reach a state where you write functions like these without needing their cheat sheet at hand.

Gotta keep studying. Every comment is welcome.

[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://james-iry.blogspot.it/2007/11/monads-are-elephants-part-4.html
[4] http://www.yuiblog.com/blog/2007/06/12/module-pattern/
[5] http://stackoverflow.com/questions/12792595/how-to-convert-this-map-flatmap-into-a-for-comprehension-in-scala

Advertisements

2 thoughts on “Handling I/O with the state monad in JavaScript

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s