Hacker News new | past | comments | ask | show | jobs | submit login
Introduction to monads in JavaScript (jcoglan.com)
155 points by Isofarro on July 2, 2012 | hide | past | favorite | 34 comments



Can anyone tell me, in what real-world practical situation, this would be a better design model than just normal IO-based logging?

Would there ever be a reason to do this in the browser? Or is this something that would be more useful in a Node.js environment, and if so, when? Or is it more theoretical than practically useful?


If we look at an impure language like JavaScript through Haskell-colored glasses, essentially every line of code in a JS program is automatically in the IO monad. Haskell's bonus is that it gives you the frequently-exercised option of writing code that's explicitly not capable of doing I/O, simply by omitting IO from its type, and having this constraint enforced by the compiler. This self-imposed restriction helps avoid the numerous problems that come along with uncontrolled side effects. But since you can't "escape" the IO monad in JavaScript, there's not much point in making it explicit by doing output in a visibly monadic way.

That being said, there are plenty of uses for the monad pattern outside of the I/O domain. That's where a lot of emphasis is placed in Haskell, because Haskell couldn't do I/O without monads, but there are tons of other useful monads that have nothing to do with side effects. As the article illustrates, two of these are Writer and List (written as [] in Haskell). Another massively useful one is Maybe, which represents nullability, but by making it explicit in a value's type we can avoid a lot of the problems that arise in "nullable by default" languages.

In some sense, jQuery is an example of a monadic library, wherein the unit function is $, which lifts its argument into the jQuery monad, and bind is represented by the chain of method calls applied to that lifted value, each of which returns a different value, still wrapped in the jQuery monad. I've been told that LINQ in the C# world works similarly (in fact, there is supposedly a lot of bleed-over of ideas from Haskell into .NET because Simon Peyton-Jones works alongside some of the .NET language designers at Microsoft Research).


> ... LINQ in the C# world works similarly (in fact, there is supposedly a lot of bleed-over of ideas from Haskell into .NET because Simon Peyton-Jones works alongside some of the .NET language designers at Microsoft Research).

Erik Meijer, the creator of LINQ, is himself a functional-programming guru. A couple of years ago, he gave a series of lectures on Haskell for MSDN's Channel 9 [0] that are a great introduction to Haskell and FP generally. Throughout the series, he points out intriguing connections between the ways of doing things in Haskell and C# that at first seem like they could not be more different.

0. http://channel9.msdn.com/Series/C9-Lectures-Erik-Meijer-Func...


> In some sense, jQuery is an example of a monadic library, wherein the unit function is $, which lifts its argument into the jQuery monad, and bind is represented by the chain of method calls applied to that lifted value, each of which returns a different value, still wrapped in the jQuery monad.

Aha. Thank you. Ever since I first learned about monads in Haskell (which is not so long ago), I kept noticing examples of such patterns in some libraries and was wondering whether it's only me who thinks there is a similarity.


I've found it easiest to understand monads as "the theoretical basis behind what a lot of languages think of as features". The purpose of understanding monads feels to me as an exercise in returning to first principles.

Naturally, this has the usual consequence of first principles: a lot of things that seem obvious are no longer Just There for you to Take For Granted.

That said, I'm not really prepared to say I understand monads. :P


This is one of the reasons why I don't use Haskell.

Every concept you mention is made more complicated thinking about it with monads. Every time I use Haskell I feel like too much mental energy is wasted on silly stuff like this.


Disclaimer: I've never used Haskell

Yeah, although the article mentions how monads eliminate some boilerplate code, the whole concept of monads is lots of boilerplate code that doesn't exist in other languages. I don't really see the point of writing something like a web server or anything that interfaces a lot with users in Haskell. Seems like its strengths are manipulating data and parallelism, but it would make more sense to use a wrapper around it to handle I/O.


Monads are important in providing well-defined semantics for code. They are a way of taking imperative code and making it functional; the semantics of functional computation are much easier to define than those of imperative code. If you were interested in proving your program correct with a deductive proof (rather than, say, statistically acceptable with tests) , monads would be very important to you.

They weren't designed to provide useful design patterns. That's why articles attempting to demonstrate them as useful design patterns often seem artificial. But I think that as the art of software engineering progresses, the problems they solve will become more important.


Let's say I have several functions I want to compose, feeding the result of one as the argument to the next. But each of these functions has some failure condition, which, if it occurs, causes the function to be unable to return a normal result. In an imperative language, I might represent that failure by returning a null reference, and I'd write something like this:

    fooResult = foo(x);
    if (fooResult == null) {
        return null;
    } else {
        barResult = bar(fooResult);
        if (barResult == null) {
            return null;
        } else {
            bazResult = baz(barResult);
            if (bazResult == null) {
                return null;
            } else {
                quuxResult = quux(bazResult);
                if (quuxResult == null) {
                    return null;
                } else {
                    return quuxResult;
                }
            }
        }
    }
I think that's a pretty common pattern: call a function and check whether it succeeded. If it did succeed, then pass its result to the next function and repeat. If it failed, then propagate the failure outwards, skipping the rest of the computation.

But that's pretty tedious and repetitive code to write. The signal to noise ratio is incredibly low. Not only that, but if I get lazy or forgetful and don't check for null in any one of those cases, my code could blow up at runtime. It would be nice if we could abstract out the pattern of error checking and propagation of errors so we didn't have to type so much boilerplate around the real meat of the computation, which is just the four function calls. Haskell's Maybe type serves precisely this purpose. The exact same code as above, in Haskell using the Maybe monad, would be:

    return x >>= foo >>= bar >>= baz >>= quux
That's it! Error propagation will happen automatically, and if no errors occur along the way, we'll get the same result at the end.

Now, you might think that there must be a lot going on behind the scenes to make that one-liner actually do what we want it to do. But there isn't really. Maybe comes for free in the standard libraries, and even if it didn't, we could trivially define it ourselves like this:

    data Maybe a = Nothing | Just a
    instance Monad Maybe where return = Just
                               Nothing >>= _ = Nothing
                               Just x >>= f = f x
That's the entire definition of the Maybe data type and its complete error propagation behavior. There's nothing more to it than that. And not only will it work in the specific example I gave, but in any situation where I have a chain of functions to call that might fail in some way. After writing that once (or not at all, since it's in the libraries), I can now apply that pattern anywhere I need it, in any program, to concisely express what took around 20 lines of onerous and error-prone repetition without the benefit of the monad.

That's how monads eliminate boilerplate, and one of the reasons why you might benefit from understanding them even if you're not a Haskell user.


First, who writes code like that? Let's try some more realistic formatting.

    fooResult = foo(x);
    if (fooResult == null) {
        return null;
    }
    barResult = bar(fooResult);
    if (barResult == null) {
        return null;
    }
    bazResult = baz(barResult);
    if (bazResult == null) {
        return null;
    }
    quuxResult = quux(bazResult);
    if (quuxResult == null) {
        return null;
    }
    return quuxResult;
Second, in most cases ignoring errors is not what you want. Knowing which function returned null, and why it returned null, is almost as important as the null itself.

Ideally functions would raise an exception instead of returning bad data (aka null) and the psuedo-code snippet above would more cleanly be written:

    fooResult = foo(x);
    barResult = bar(fooResult);
    bazResult = baz(barResult);
    return quux(bazResult);
Or to match your single line:

    return quux(baz(bar(foo)));
The exception would be handled in the same place that handles the eventual Nothing value returned in Haskell.


I concede on the pseudocode formatting point. Upon rereading, that is uglier than necessary.

The trouble with exceptions is that, unless you're referring to Java-style checked exceptions, there's nothing that forces you to handle them. You can still forget that the exception can occur, and then your code will blow up at runtime. And in one sense, exceptions are even worse than the repetitive if-then clauses: if statements at least handle the failure right there at the call site, whereas exceptions let you move your error handling code to some other place in the call stack, non-local to where the actual error might occur. There are advantages as well, for sure, but I see this as potentially very confusing.

Haskell has exceptions but most people prefer to avoid them, favoring the use of MonadError instances (such as Maybe) instead, since they make the potential failure highly explicit and impossible to forget about or ignore. And while I don't think using Maybe is at all the same as ignoring errors, I suppose I see how it could be construed that way. That's why there's Either as well, which allows you to associate some piece of data with the failure. So you could use the Either String monad to pass back an error message on failure, or Either [String] to pass a list of them, or Either (IO ()) to specify an action to be taken in response to the failure, or whatever you want. I guess that ends up being a lot like exceptions, except for the fact that you can't ignore or forget them, so your code is still verifiably safe at runtime, and there is nice syntactic sugar from the Monad class (do notation, >>= chaining, etc.) to make them concise and elegant to use without cluttering your code.


So, Java's HashMap.get() should throw a checked exception whenever the value is not found in the map? That would sure eliminate a lot of boilerplate code :)

Aren't exceptions meant to be used for, well, exceptional cases only, i.e. when no matter what, execution really can't be continued? It makes sense for a lot of functions to return some sort of "Nothing" value instead of raising an exception, but the problem is that in many languages there is no explicit "Nothing" value, so people just abuse null.

You can have Maybe in Java too, but getting out a value or a Nothing out of a Maybe value is just not enforced by the compiler due to the lack of algebraic data types and pattern matching; still, it is an improvement over null hell. On a side note, Maybe is called Option in Scala.

By the way, exceptions are monads, they are just predefined in most languages in a way you can not change. If you want a lengthy Java centric read about that I would strongly recommend checking out [1]. Ant here's another if you're ok with reading Haskell [2].

Also for the record, in Haskell you can use the ErrorMonad in place of the Maybe monad if you want precise error reporting capabilities.

[1] http://apocalisp.wordpress.com/2008/05/16/thrower-functor

[2] http://www.haskell.org/haskellwiki/Exception


Exceptions can be modeled by a type like "Maybe" that simply also has the error information in it. So instead of a "Nothing", you have "Left err" with the "err" information in it.

The nice thing is that the same example using >>= above would work with Either's too, because it will just use the monad instance of Eithers, and you will get all the error information that way.

Exceptions, when represented this way, become a way that the error is handled by the caller rather than a different way to return. That way, the result of the function is well-described by its type.


you can implement exceptions with error monad.


Clearly having composable functions is a powerful idea. That's essentially part of the reason shell scripts are so successful. A well behaved shell script is a F(Lines)->Lines. which means you could actually write the above code like this:

x|foo|bar|baz|quux

And any step in the pipeline produced an empty output, that would be automatically carried through. This is one reason why having a.b.c through a NPE in java is not always ideal. In objective-c you can pass any message to nil, so [[a b] c] is defined even if a.b is nil. Imagine what a pain it would be if `cat file | grep a | grep b` blew up because file was empty or a was not found.


I do a lot of Javascript and I would do it this way:

    [foo,bar,baz,quux].reduce(function(p,c,i){ 
        return p == null ? null : c(i === 1 ? x : p) 
    })
And you could abstract it in the Array prototype

    Array.prototype.linearExe = function(x){
        return this.reduce(function(p,c,i){ 
            return p == null ? null : c(i === 1 ? x : p)  
        })
    }
To use it like this

    [foo,bar,baz,quux].linearExe(x)


True, depending on your language, you can probably get the imperative version to be shorter than my pseudo-C implementation.

But that accumulating function you're passing to reduce? That's essentially just a JavaScript version of the bind (>>=) operator for Maybe. In fact, in Haskell, I'd express what you wrote as:

    foldl (>>=) x [foo, bar, baz, quux]
foldl is Haskell's version of reduce, so that's almost exactly the same as your code. You're using a monad to shorten your code, you're just not being obvious about it!


[foo, bar, baz, quux] might be problematic if the types of these functions are not homogenous.

  foo >=> bar >=> baz >=> quux
is ok and >=> is not a much-worse separator than , here...


If you take this pattern and generalize it to having arbitrary behavior between each function call, you basically have monads where the [foo,bar,baz,quux] bit sort of acts like do notation in Haskell. The exact details might not be entirely the same, but it is exactly the same idea: you can control how a bunch of functions get composed.

So you'd have code that looks just like yours, but depending on which "monad instance" you parametrize it with, it could have different behavior. So you could uniformly represent code that could return null, code that could have multiple results or even parser code. And, very importantly, you could write other functions that act over all these different behaviors. So you could implement a reduceM function that would support a reducer that could return null, or one that could return many elements, or plenty of other possible behaviors in a uniform way.


The Writer Monad probably isn't too useful in any impure language, and IMO was a poor choice by the author. If you read the last few paragraphs though, you're introduced to the List Monad (the bit about HTML nodes), which is useful in impure languages.

Another example I would have liked to see is the Maybe Monad, which allows composition of functions that might return a value, or null/undefined.


The problem is that the tutorial was transliterated from Haskell. So while it's useful for understanding the idea behind monads, the examples are not very motivating in a language like JavaScript. The one interesting example in the article for actual JavaScript use is probably the list monad which lets you compose functions returning an arbitrary number of results rather than just one (these functions are often called "nondeterministic").

However, it's possible to imagine other useful monads for JavaScript use. For example, I think we can abstract over CPS (continuation-passing style, like asynchronous functions in Node.js) functions using a monad.

This will involve changing our idea of CPS a little bit: instead of having a function f(x, k) where x is the argument and k is the callback, let's have a function f(x) which returns a function g(k) with x and k being the argument and callback respectively. Now we have to define the basic monad functions on it.

First, let's start with unit (which is called "return" in Haskell). The idea is simple: we want to go from some value to a function accepting a callback. What is a reasonable way to do this? Let's define it in a trivial way: we go from x to a function that, given a callback, immediately calls it with x. So:

    CPS.unit = function (x) {
      return function (k) {
        k(x);
      };
    };
Next, we want to define bind. Now, what will bind do? The core idea is this: given a wrapped value m x and a function f: x → m y, we need to apply f to the wrapped value. Now, in this context, the "wrapped value" is a function accepting a callback. Essentially, this wrapped value is a promise to provide x at some point in the future. So we want to take this "promise" and get a new promise for the result of calling another CPS function on it. Here is a way to do this:

    CPS.bind = function (f, x) { // f: x → m y, x: m x
      return function (k) {
        x(function (x_val) {
          f(x_val)(k);
        });
      };
    }; 
Admittedly, this code is a little confusing; I will try to explain it. The basic idea is simple: we create a new promise (the outermost returned function) that will trigger after x triggers and will then pass both the result of x (x_val) and the given callback (k) into f. That is, we get a promise of the result of f called with the eventual value of x.

This lets us bind together all these asynchronous values so that the result is still asynchronous. This makes managing "callback hell" simpler: instead of having a ton of nested callbacks, we can have a string of calls to bind. We also get a bunch of functions for free. For example, let's say you have a deferred x and want to apply a function to the result. This is essentially mapping the function over the deferred value. You could write it like this:

    CPS.map = function (f, x) {
      return CPS.bind(compose(CPS.unit, f), x);
    }
However, the true power of monads is that this map function works exactly the same way on every monad. So you could rewrite it like this:

    Monad.prototype.map = function (f, x) {
      return this.bind(compose(this.unit, f), x);
    }
then make all your monad "types" (for lack of a better word) inherit from Monad. So the CPS type I showed here would get map for free, but so would an analogous List type.

Moreover, this is true for a whole bunch of useful functions. For example, you would be able to generalize reduce to accept a reducer function that behaves like a monad instead of like a normal function (you could call it reduceM). So you would then be able to reduce using an asynchronous function! I think that's pretty cool.

Note that it isn't enough just to write unit and bind to get a monad--the functions also have to follow some laws. If these laws aren't followed, you get all sorts of weird behavior with your monad. I think my CPS instance follows these laws, but I'm too lazy to check just this moment. I'll leave it as an exercise to the reader (I've always wanted to say that).

The reason we have to do some extra legwork (like creating the CPS object) is that JavaScript is not good at differentiating between types. Particularly, there is no way to consider only CPS functions. Additionally, there is a valid monad instance for all functions which behaves differently from the CPS one, and there would be no way to differentiate between the two without making it explicit. Now, I'm sure there is a neat way to make bind and unit methods of appropriate types, but that would make the examples even more complicated and I don't want to think about it right now :P.

In summary: monads let you generalize over a bunch of different concepts, not just IO. In particular, you can use monads to write code that works generically over CPS functions and nondeterministic functions and a bunch of others.

EDIT: I forgot to note: promises already have a well-known meaning in JavaScript. I don't actually know that meaning because I've never used them. The only reason I use the word is because I couldn't think of anything better to call them. It's likely the semantics of existing promises and the semantics of the objects I described are actually different, but they do serve the same purpose.


The problem with monads is that its hard to justify the whole concept until you start wanting abstract some code to work with more then one monad.

That said, specific monads actually show up pretty often. A very important example is the Promise monad used by some Javascript async libraries:

(for example, see https://github.com/kriskowal/q or http://dojotoolkit.org/documentation/tutorials/1.6/promises/)

Basically, creating a new promise is the monadic "return" and the "promise.then" method is the monadic "bind" (or "fmap", if the callback returns a normal value instead). I found that knowing a bit about monads helped me work better with the promises from the Dojo framework but I guess your mileage may vary...


Generalizing Monad in a language without return-type polymorphism is hard. How do you implement "return" (unit)?


The best way would be to specify the return type directly. This is unfortunate, but it is how basically any language (that I know) save Haskell would do it.

So instead of having a return function, you would use something like List.return or Maybe.return or whatever. This is the same way you would solve the problem of read (that is, the opposite of toString): Double.parse, Integer.parse and so on. When you have a polymorphic function, you would pass in the type as appropriate.

Clearly, this is not ideal. However, this is basically what the Haskell compiler does for you with typeclasses--loosely speaking, a function polymorphic over a typeclass gets transformed into a function accepting an instance and its normal arguments.

In OCaml, you could solve this problem with a functor. So your polymorphic module is parametrized on another module that provides the return and bind functions. I personally like this approach less than Haskell's, but it is more flexible (for better or worse): you can have different modules passed in for the same type. In Haskell, to get different behavior for the same type using typeclasses, you'd have to create a new type with newtype.

So in short, it isn't impossible: you just have to do more manually than you do in Haskell.


If you want to write functions that are polymorphic on any monad, they'd have to take a type argument explicitly, which also reduces their cost-effectiveness.

I am not sure Monads are a cost-effective abstraction in most languages.


If you like this sort of thing, check out the Arrowlets[1] library for JavaScript. It uses "arrows", an abstraction in a similar vein to monads, to make CPS functions and event handling neater (among other things).

[1]: http://www.cs.umd.edu/projects/PL/arrowlets/

From playing around with it, I think the arrows from that library are more useful to practical JavaScript programming than monads.


Since you're familiar with arrowlets, would you mind having a look at samsara?

[samsara]: http://lcfrs.org/samsara/docs/dragndrop.html


That seems cool--CoffeeScript's syntax is definitely better-suited for this sort of thing than JavaScript's!

The main page says the library's in CoffeeScript, but the drag and drop example uses JavaScript. Do you have a similar (or even the same) example in CoffeeScript? I'd like to see what it looks like.


There are two parts to example: the plain functions, and the composition. CoffeeScript can make the plain functions look different, but the composition is the strangest looking; I need to find a better syntax for representing a directed graph in code, and CoffeeScript doesn't help with that part.


Considering that arrows are a generalization of monads, that shouldn't be a surprise.


re the comment in the original article about monadic javascript: take a look at roy. http://roy.brianmckenna.org


Wow, I now understand monads. This article nailed it.


    ...it helps you spot accidental complexity...Being able to spot and extract
    such boilerplate can radically improve the clarity of your code.
I think a second version of this tutorial in CoffeeScript would really shine a light on how CS is the best of JavaScript. Monads and FP are a breeze -- practically encouraged -- in CoffeeScript. It really removes the cruft of JS syntax and lets me focus on well-designed code, and I've found myself using similar patterns since I switched to CS. I code faster and (contrary to what I expected) debugging is much easier.


I've read many attempts to explain Monads by now, but this is the first time I think I actually "got" it. Well done!




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: