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.
Commentary