Skip to main content

There Will Be Monads

Posted by cayhorstmann on June 18, 2011 at 9:37 PM PDT

I finished my "modern programming languages" course at the Ho Chi Minh City University of Technology. We covered metaprogramming (with Ruby and Rails), continuations (with Racket and Scala), concurrency (with Scala and Clojure), and finished off with a dose of Haskell to see type inference and type classes in action. Here are the hardy souls who stuck it out until the end. (All but one, that is--one is behind the camera.)

What's the fun of teaching if you don't also get to learn something new? It was about time for me to understand the fuss about monads. The blogosphere is awash in articles proclaiming that monads are elephants, monads are burritos, monads are space suits, and so on. Naturally, these analogies left me unenlightened.

Along the way, I made the mistake of looking for tutorials that tried to explain monads using Scala (such as this one). I should have known better. A few years ago, I had been baffled by blog posts that tried to teach continuations with C++ or Java, with a lot of pointless machinery and little to show for. Finally, I took a deep breath and figured out how continuations work in Scheme. It is always best to learn these things in their natural habitat.

Ok, time to figure out monads in Haskell. This article is very good, but I kept scratching my head at the monad laws

    return x >>= f ≡ f x
    c >>= return ≡ c
    c >>= (λx . f x >>= g) ≡ (c >>= f) >>= g

I could verify the laws for a bunch of monads, but they seemed arbitrary and ugly. Then I ran across this page, with a casual remark that the laws look much better when formulated in terms of the "Kleisli composition operator" >=>:

    f >=> return ≡ f
    return >=> g ≡ g
    (f >=> g) >=> h ≡ f >=> (g >=> h)

My ah-ha moment came when I saw the signature of that mysterious operator:

(a -> m b) -> (b -> m c) -> (a -> m c)

Here, we have two functions that take ordinary values and turn them into values in some alternate universe (Maybe t or IO t or whatever). And now we want to compose two of these functions to get another. Of course we do.

I instantly realized that, like so many other people, I had invented monads before. It was in a cell phone library that was shared between Android and BlackBerry apps. I had to deal with multi-step user interface actions. In each step, the user was asked some question. The answer only emerged when the user did some platform-specific input. I needed a mechanism for doing multiple steps in a row. I built a mini-framework of actions, each of which had an event handler for delivering the answer. Actions could be composed. The first handler kicked off the second action and the second handler returned the final answer. Yes, composition was associative :-) Unbeknownst to myself, that was my first monad.

What's the point? Had I known what monads are, I would have arrived at my design more quickly. I would have picked off-the-shelf convenience functions instead of inventing my own as the need became apparent. Monads aren't burritos, they are a design pattern.

I could go on and explain, but I won't, for the reason that is so ably expressed here.

Related Topics >>

Comments

<p>Interesting, so Haskell allows variable names like ...

Interesting, so Haskell allows variable names like "λ" in its code. Guess only with Unicode and UTF-8 enabled?

If Java did on a broader scale, initiatives to provide it better support for datatypes like Measurements and Units may work, which failed earlier due to the limited mindset, platform and modularity of Java SE.

<p>I have no idea whether Haskell allows for &lambda;. I ...

I have no idea whether Haskell allows for λ. I just translated the Haskell syntax into something that I thought would be more familiar to the world at large.

I think it is hopeless to wait for Java to support such things. I just read a depressing debate on the lambda-dev mailing list on whether to use ^ or # or whatever for anonymous functions--the suggestion to use λ was shouted down immediately.

Scala does allow for Unicode symbols, even for arrows. In the first draft of my "Scala for the Impatient" book, I happily used ⇒ instead of =>. But the readers on Safari weren't so happy. When they tried to paste it into Eclipse, bad things happened. On Windows. And the Mac. It works fine on Linux, of course. And people kvetch on how you should type such a thing. In Linux, no problem--you just add an entry to ~/.XCompose. In Windows and Mac OS X, good luck. So I gave up and went back to =>. It's sad--after a quarter century of Unicode, the "mainstream" OSs still make you worry about the Windows 1252 code page and MacRoman.