Writing Monads in JavaScript

10 Oct 2015

I've recently started exploring what monads could look like in JavaScript. If you don't know what a monad is, here is one of my favorite videos on the topic. (Beware, it's an hour long video. And you will have to spend a little bit of time digesting his information.)

In short, a monad is a wrapper around a value that may have some unintended consequences, in order to perform composable, safe operations. monads are constructs from functional programming, and are used everywhere in functional langauges. It's about damn time that we start taking monads seriously in JavaScript as well.

I've taken a great deal of inspiration from Scala in my approach to monads in JavaScript. This started out as purely an expirement, but the more I work with these ideas, the more excited I am. I believe monads are perfectly feasible, and should be used in JavaScript. Some of the benefits of monads is they eliminate the need for a null value, and the need to throw errors.

Faux-pattern matching

In Scala, you can create partial functions that match based on type, like so:

foo match {
  case Some(bar) => ???
  case None => ???
}

This is pretty useful for when working with algebraic types. Although we don't have such syntax in JavaScript, it's possible to do something like this:

foo().match({
  Some (bar) { ... },
  None () { ... }
})

The drawbacks are the lack of compile-time syntax and type checks. However, it does make using Option more practical. In the same vein, here's faux-pattern matching for an Either.

foo().match({
  Left (bar) { ... },
  Right (baz) { ... }
})

Parsers and Serializers

I think things like Option are totally useless unless there's an easy way to interop with vanilla JS objects. There needs to be some repeatable way to serialize and deserialize to monadic values. For example:

{
  "foo": "bar",
  "biz": null
}

Should serialize into:

{
  "foo": Some("bar"), // or just "bar" if we expect this value to always exits.
  "biz": None()
}

To that endeavor, my ideas is to create parsers based off of Reads objects. The API looks like this:

const definition = M.define({
  "foo": Option.as(M.string),
  "biz": Option.as(M.string)
});

definition.parse({
  "foo": "bar",
  "biz": null
}).map((parsed) => ...); // parsed is now { "foo": Some(bar), "biz": None() }

In this example, the object passed to M.define is an object of key-Reads pairs. The return value of M.define is a Reads itself, so this can be freely nested. M is just a placeholder name until I figure out what to call this library of mine.

For some real world examples, here's a potential way to implement it in Angular

module.factory("User", function($http){
  class User {
    constructor (props) {
      angular.extend(this, props);
    }
  };

  const definition = M.define({
    firstName: M.string,
    lastName: Option.as(M.string)
  });

  /**
   * This would return a Promise<User>
   */
  User.find = function(id){
    return $http.get(`/users/${ id }`).then(({ data }) => {
      return definition
      .parse(data)
      .map((parsed) => new User(parsed))
      .toPromise();
    })
    .then(function(user){
      // here, a user is instantiated
    })
    .catch(function(err){
      // here, err might be a parsing error.
    });
  };

  return User;
});

Here is the repository I'm currently working off of to explore all these ideas. Feel free to check out the source code, and offer suggestions. I'm quite excited about it.

One more thing: a JavaScript Promise is a monad-like type for future operations. It doesn't fully behave like a monad, because you cannot have a Promise<Promise>. However, it takes almost the same approach as a monad. Some further reading/watching: