From JQuery to Monads

Sam Ruby on JQuery:

The notable thing about this is that despite all of the asynchronous events taking place, the code is sequential (nested, but sequential), and that the JSON results of the AJAX call are immediately available to the function that is invoked when the selection changes.

Yep. They call this continuation-passing style (though callback passing style might be more appropriate).

Reminds me of monads.

Seriously. The bind operator (>>=) basically takes a monad, a callback, and returns a new monad. You often end up chaining a bunch of binds together. Let’s see an example.

Consider a monadic Parsec parser which takes a string of balanced parenthesis as input and returns a number indicating how deeply nested they are. If you use, bind explicitly, here’s the ugly, ugly way you’d define this parser.

nesting :: Parser Int
nesting = char '(' >>= _ ->
    nesting >>= \n ->
      char ')' >>= _ ->
        nesting >>= \m ->
          return (max (n + 1) m)
  <|> return 0

It’s almost as though you wrote the Ruby code:

nesting = alt(char '(' do
  nesting do n
    char ')' do
      nesting do m
        [(n + 1), m].max
      end
    end
  end
end).with do 0 end

Gross, huh? In Haskell there’s special notation for binds used in sequence. Instead of:

m >>= \a -> fa

write:

do
  a <- m
  fa

Similarly, instead of:

m >>= _ -> f

write:

do
  m
  f

Then the nasty:

nesting = char '(' >>= _ ->
    nesting >>= \n ->
      char ')' >>= _ ->
        nesting >>= \m ->
          return (max (n + 1) m)
  <|> return 0

becomes the nice:

nesting = do
    char '('
    n <- nesting
    char ')'
    m <- nesting
    return (max (n + 1) m)
  <|> return 0

The yummy taste of syntactic sugar.