A simple introduction to why Monads are useful
In the programming language F#, monads are called "computational expressions" mostly so people aren't scared away. But I think all this fear and mysticism around the dreaded "M-word" need not be so. So in this post, I'm going to attempt to put a small crack in the curse, not by attempting to explain all of monad theory in general, but instead by thoroughly diving into a concrete example of a monad in a specific language: the Maybe monad in JavaScript[1]. If you've been putting off learning about monads - or maybe have never even heard of them until now - then this post is for you. It will provide just enough material to give you a sense of what monads are and what they can do. From there you should have a solid stepping off point from which you can jump into reading something like this without trepidation. If you're a seasoned developer, chances are you have already used monads in your daily practice without even realizing it. For instance, a jQuery Deferred object is a monad. So is jQuery Ajax, as well as Bacon.js EventStream. So this shouldn't be too hard to follow. On occasion, I will reference similarities between the JavaScript example and its counterparts in the programming language Haskell. I do this only because most formal literature on monads references Haskell, and it helps to become familiar with the language. Feel free to skip these parts if you prefer. Maybe We Have a Problem After the Identity monad, the Maybe monad is perhaps one of the simplest examples of a monad available. It's also quite useful. The Maybe monad provides an elegant solution to the common problem of multiple nested null checks in code. Consider the following trivial example: var person = { "name":"Homer Simpson", }, val: function() { }, maybe: function(def, fn) { if (state != Nothing) { The unary return operation takes a value from a plain type a and puts it into a monadic container of type M a; the bind operation chains a monadic value of type M a with a function of type a ° M b to create a monadic value of type M a can be thought of as an action that returns a value of type M b. Monad laws For a monad to behave correctly, the definitions must obey a few axioms, together called the monad laws.[11] The = symbol indicates equivalence between two Haskell expressions in the following text. return >=> g = g f >=> return = f (f >=> g) >=> h = f >=> (g >=> h) fmap and join Although Haskell defines monads in terms of the return and bind functions, it is also possible to define a monad in terms of return and two other operations, join and fmap. This formulation fits more closely with the original definition of monads in category theory. The fmap operation, with type (t°u ) ° M t°M u,[12] takes a function between two types and produces a function that does the "same thing" to values in the monad. The join operation, with type M (M t)°M t, "flattens" two layers of monadic information into one. The two formulations are related as follows: fmap f m = m >>= (return . f) join n = n >>= id m >>= g = id fmap (f . g) = join (fmap g m) Here, m has the type M t, n has the type M t, n has the type M t, n has the type M t, n has the type M t, n has the type M t, n has the type M (M r), f has the type t ? u, and g has the type t ° M v, where t, r, u and v are underlying types. The fmap function is defined for any functor in the category of types and functions, not just for monads. It is expected to satisfy the functor laws: fmap id = join (fmap g m) Here, m has the type M t, n has the type M (M r), f has the type t ° M v, where t, r, u and v are underlying types. The fmap function is defined for any functor in the category of types and functions, not just for monads. It is expected to satisfy the functor laws: fmap id = a + (b + c) m + m0 "street":"123 Fake St.", console.log(state); } }; var Something = function(value) { return Nothing; return Something(value); }; With this new bind method we can more elegantly re-write our code: var state = Maybe(person).bind(function(p) { return p["address"]; }).bind(function(a) { return a["state"]; }); if (state == Nothing) { console.log("State unknown"); } else { console.log(state); } Certainly this is better than before, but can we do better? (Note: If you're keeping score, then you'll note the type signature of our bind differs from Haskell's >>=. Haskell's bind operator is of type m a -> (a -> m b) -> m b, whereas ours is m a -> (a -> m b) -> m b, whereas ours is m a -> (a -> m b) -> m b, whereas ours is m a -> (a -> b) -> m b. That is, we should be able to sequence monads together through composition. You may remember that function composition is the application of one function to the result of another. Mathematically, given two functions g and f, the composition of g of f is: (g°f)(x) = g(f(x)) In the case of Maybe, we need some way to take multiple Maybes and combine, chain or bind them together in a meaningful way. This way, if one Maybe is Nothing we can short-circuit our computation and stop at Nothing, otherwise we can continue on our way, essentially replicating what the && provides in our first example. (Technically, in JavaScript the computation does not short-circuit as it would in a lazy language like Haskell, but the effect is the same.) We can do this by introducing a method on Maybe called bind (in Haskell, this is the >>= operator) that makes specific use of function composition. This bind method applies a function to the value contained by a Maybe and returns a new Maybe that contains the value of the second. We should be able to determine our next action based on the value produced by the action on the left. The resulting combined action, when performed, performs the first action, then evaluates the function with the first action's return value, then performs the second action, and finally returns the second action's value. An example of the use of this operator in Haskell would be getLine >>= putStrLn, which reads a single line of text from standard input and echoes it to standard output. Note that the first operator, >>, is just a special case of this operator in Haskell would be getLine >>= putStrLn, which reads a single line of text from standard input and echoes it to standard output. Note that the first operator, >>, is just a special case of this operator in Haskell would be getLine >>= putStrLn, which reads a single line of text from standard input and echoes it to standard output. Note that the first operator, >>, is just a special case of this operator in which the return value of the first action is ignored and the selected second action is always the same. It is not necessarily obvious that the three preceding operations, along with a suitable primitive set of I/O operations, allow us to define any program action whatsoever, including data transformations (using lambda expressions), if/then control flow, and looping control flows (using recursion). We can write the above example as one long expression: main = putStrLn "What is your name?" >> getLine >>= \name -> putStrLn ("Nice to meet you, " ++ name ++ "!") The pipeline structure of the bind operator ensures that the getLine and putStrLn operations get evaluated only once and in the given order, so that the side-effects of extracting text from the input stream and writing to the output stream are correctly handled in the functional pipeline. This remains true even if the language performs out-of-order or lazy evaluation of functions. Clearly, there is some common structure between the I/O definitions and the Maybe definitions, even though they are different in many ways. Monads are an abstraction upon the structures described above, and many similar structures, that finds and exploits the commonalities. The general monad concept includes any situation where the programmer wants to carry out a purely functional computation while a related computation is carried out on the side. Formal definition A monad is a construction that, given an underlying type system, embeds a corresponding type system (called the monadic type system) into it (that is, each monadic type acts as the underlying type). This monadic type system preserves all significant aspects of the underlying type system, while adding features particular to the monad.[b] The usual formulation of a monad for programming is known as a Kleisli triple, and has the following components: A monad is created by defining a type constructor M and two operations, bind and return (where return is often also called unit): The unary return operation takes a value from a plain type a and puts it into a container using the constructor, creating a monadic value: M a. The function then creates a new monadic value M b that can be fed to the next bind operators composed in the pipeline. With these elements, the programmer composes a sequence of function calls (the "pipeline") with several bind operators chained together in an expression. Each function call transforms its input plain type value, and the bind operator handles the returned monadic value, which is fed into the next step for you. In this way, you don't have to keep writing loops all over the place when dealing with multiple results. The bind function "automatically" does all that for you. (The List Monad.) Extending this idea, you can implement "exceptions". (The Error Monad or Exception Monad.) Because you're defining them yourself rather than it being a language feature, you can define how they work. (E.g., maybe you want to ignore the first two exceptions and only abort when a third exception is thrown.) You can implement "continuations" as a monad. This allows you to break people's minds!