Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Monad in plain English? (For the OOP programmer with no FP background)

People also ask

What is a monad in oops?

In terms of OO programming, a monad is an interface (or more likely a mixin), parameterized by a type, with two methods, return and bind that describe: How to inject a value to get a monadic value of that injected value type; How to use a function that makes a monadic value from a non-monadic one, on a monadic value.

What is monad and monoid?

A monad can be seen as a combination of a functor (we have M[A] with a map that permits us to apply f to each element in M[A] and obtain M[M[B]]) and a monoid (that permits to flatten M[M[B]] into M[B] by means of the associative operator: e.g., concatenation in the case of lists).

What is a monad in simple terms?

In functional programming, a monad is a software design pattern with a structure that combines program fragments (functions) and wraps their return values in a type with additional computation.

What is a monad type?

In Haskell a monad is represented as a type constructor (call it m ), a function that builds values of that type ( a -> m a ), and a function that combines values of that type with computations that produce values of that type to produce a new computation for values of that type ( m a -> (a -> m b) -> m b ).


UPDATE: This question was the subject of an immensely long blog series, which you can read at Monads — thanks for the great question!

In terms that an OOP programmer would understand (without any functional programming background), what is a monad?

A monad is an "amplifier" of types that obeys certain rules and which has certain operations provided.

First, what is an "amplifier of types"? By that I mean some system which lets you take a type and turn it into a more special type. For example, in C# consider Nullable<T>. This is an amplifier of types. It lets you take a type, say int, and add a new capability to that type, namely, that now it can be null when it couldn't before.

As a second example, consider IEnumerable<T>. It is an amplifier of types. It lets you take a type, say, string, and add a new capability to that type, namely, that you can now make a sequence of strings out of any number of single strings.

What are the "certain rules"? Briefly, that there is a sensible way for functions on the underlying type to work on the amplified type such that they follow the normal rules of functional composition. For example, if you have a function on integers, say

int M(int x) { return x + N(x * 2); }

then the corresponding function on Nullable<int> can make all the operators and calls in there work together "in the same way" that they did before.

(That is incredibly vague and imprecise; you asked for an explanation that didn't assume anything about knowledge of functional composition.)

What are the "operations"?

  1. There is a "unit" operation (confusingly sometimes called the "return" operation) that takes a value from a plain type and creates the equivalent monadic value. This, in essence, provides a way to take a value of an unamplified type and turn it into a value of the amplified type. It could be implemented as a constructor in an OO language.

  2. There is a "bind" operation that takes a monadic value and a function that can transform the value, and returns a new monadic value. Bind is the key operation that defines the semantics of the monad. It lets us transform operations on the unamplified type into operations on the amplified type, that obeys the rules of functional composition mentioned before.

  3. There is often a way to get the unamplified type back out of the amplified type. Strictly speaking this operation is not required to have a monad. (Though it is necessary if you want to have a comonad. We won't consider those further in this article.)

Again, take Nullable<T> as an example. You can turn an int into a Nullable<int> with the constructor. The C# compiler takes care of most nullable "lifting" for you, but if it didn't, the lifting transformation is straightforward: an operation, say,

int M(int x) { whatever }

is transformed into

Nullable<int> M(Nullable<int> x) 
{ 
    if (x == null) 
        return null; 
    else 
        return new Nullable<int>(whatever);
}

And turning a Nullable<int> back into an int is done with the Value property.

It's the function transformation that is the key bit. Notice how the actual semantics of the nullable operation — that an operation on a null propagates the null — is captured in the transformation. We can generalize this.

Suppose you have a function from int to int, like our original M. You can easily make that into a function that takes an int and returns a Nullable<int> because you can just run the result through the nullable constructor. Now suppose you have this higher-order method:

static Nullable<T> Bind<T>(Nullable<T> amplified, Func<T, Nullable<T>> func)
{
    if (amplified == null) 
        return null;
    else
        return func(amplified.Value);
}

See what you can do with that? Any method that takes an int and returns an int, or takes an int and returns a Nullable<int> can now have the nullable semantics applied to it.

Furthermore: suppose you have two methods

Nullable<int> X(int q) { ... }
Nullable<int> Y(int r) { ... }

and you want to compose them:

Nullable<int> Z(int s) { return X(Y(s)); }

That is, Z is the composition of X and Y. But you cannot do that because X takes an int, and Y returns a Nullable<int>. But since you have the "bind" operation, you can make this work:

Nullable<int> Z(int s) { return Bind(Y(s), X); }

The bind operation on a monad is what makes composition of functions on amplified types work. The "rules" I handwaved about above are that the monad preserves the rules of normal function composition; that composing with identity functions results in the original function, that composition is associative, and so on.

In C#, "Bind" is called "SelectMany". Take a look at how it works on the sequence monad. We need to have two things: turn a value into a sequence and bind operations on sequences. As a bonus, we also have "turn a sequence back into a value". Those operations are:

static IEnumerable<T> MakeSequence<T>(T item)
{
    yield return item;
}
// Extract a value
static T First<T>(IEnumerable<T> sequence)
{
    // let's just take the first one
    foreach(T item in sequence) return item; 
    throw new Exception("No first item");
}
// "Bind" is called "SelectMany"
static IEnumerable<T> SelectMany<T>(IEnumerable<T> seq, Func<T, IEnumerable<T>> func)
{
    foreach(T item in seq)
        foreach(T result in func(item))
            yield return result;            
}

The nullable monad rule was "to combine two functions that produce nullables together, check to see if the inner one results in null; if it does, produce null, if it does not, then call the outer one with the result". That's the desired semantics of nullable.

The sequence monad rule is "to combine two functions that produce sequences together, apply the outer function to every element produced by the inner function, and then concatenate all the resulting sequences together". The fundamental semantics of the monads are captured in the Bind/SelectMany methods; this is the method that tells you what the monad really means.

We can do even better. Suppose you have a sequences of ints, and a method that takes ints and results in sequences of strings. We could generalize the binding operation to allow composition of functions that take and return different amplified types, so long as the inputs of one match the outputs of the other:

static IEnumerable<U> SelectMany<T,U>(IEnumerable<T> seq, Func<T, IEnumerable<U>> func)
{
    foreach(T item in seq)
        foreach(U result in func(item))
            yield return result;            
}

So now we can say "amplify this bunch of individual integers into a sequence of integers. Transform this particular integer into a bunch of strings, amplified to a sequence of strings. Now put both operations together: amplify this bunch of integers into the concatenation of all the sequences of strings." Monads allow you to compose your amplifications.

What problem does it solve and what are the most common places it's used?

That's rather like asking "what problems does the singleton pattern solve?", but I'll give it a shot.

Monads are typically used to solve problems like:

  • I need to make new capabilities for this type and still combine old functions on this type to use the new capabilities.
  • I need to capture a bunch of operations on types and represent those operations as composable objects, building up larger and larger compositions until I have just the right series of operations represented, and then I need to start getting results out of the thing
  • I need to represent side-effecting operations cleanly in a language that hates side effects

C# uses monads in its design. As already mentioned, the nullable pattern is highly akin to the "maybe monad". LINQ is entirely built out of monads; the SelectMany method is what does the semantic work of composition of operations. (Erik Meijer is fond of pointing out that every LINQ function could actually be implemented by SelectMany; everything else is just a convenience.)

To clarify the kind of understanding I was looking for, let's say you were converting an FP application that had monads into an OOP application. What would you do to port the responsibilities of the monads into the OOP app?

Most OOP languages do not have a rich enough type system to represent the monad pattern itself directly; you need a type system that supports types that are higher types than generic types. So I wouldn't try to do that. Rather, I would implement generic types that represent each monad, and implement methods that represent the three operations you need: turning a value into an amplified value, (maybe) turning an amplified value into a value, and transforming a function on unamplified values into a function on amplified values.

A good place to start is how we implemented LINQ in C#. Study the SelectMany method; it is the key to understanding how the sequence monad works in C#. It is a very simple method, but very powerful!


Suggested, further reading:

  1. For a more in-depth and theoretically sound explanation of monads in C#, I highly recommend my (Eric Lippert's) colleague Wes Dyer's article on the subject. This article is what explained monads to me when they finally "clicked" for me.
    • The Marvels of Monads
  2. A good illustration of why you might want a monad around (uses Haskell in it's examples).
    • You Could Have Invented Monads! (And Maybe You Already Have.) by Dan Piponi
  3. Sort of, "translation" of the previous article to JavaScript.
    • Translation from Haskell to JavaScript of selected portions of the best introduction to monads I’ve ever read by James Coglan


Why do we need monads?

  1. We want to program only using functions. ("functional programming" after all -FP).
  2. Then, we have a first big problem. This is a program:

    f(x) = 2 * x

    g(x,y) = x / y

    How can we say what is to be executed first? How can we form an ordered sequence of functions (i.e. a program) using no more than functions?

    Solution: compose functions. If you want first g and then f, just write f(g(x,y)). OK, but ...

  3. More problems: some functions might fail (i.e. g(2,0), divide by 0). We have no "exceptions" in FP. How do we solve it?

    Solution: Let's allow functions to return two kind of things: instead of having g : Real,Real -> Real (function from two reals into a real), let's allow g : Real,Real -> Real | Nothing (function from two reals into (real or nothing)).

  4. But functions should (to be simpler) return only one thing.

    Solution: let's create a new type of data to be returned, a "boxing type" that encloses maybe a real or be simply nothing. Hence, we can have g : Real,Real -> Maybe Real. OK, but ...

  5. What happens now to f(g(x,y))? f is not ready to consume a Maybe Real. And, we don't want to change every function we could connect with g to consume a Maybe Real.

    Solution: let's have a special function to "connect"/"compose"/"link" functions. That way, we can, behind the scenes, adapt the output of one function to feed the following one.

    In our case: g >>= f (connect/compose g to f). We want >>= to get g's output, inspect it and, in case it is Nothing just don't call f and return Nothing; or on the contrary, extract the boxed Real and feed f with it. (This algorithm is just the implementation of >>= for the Maybe type).

  6. Many other problems arise which can be solved using this same pattern: 1. Use a "box" to codify/store different meanings/values, and have functions like g that return those "boxed values". 2. Have composers/linkers g >>= f to help connecting g's output to f's input, so we don't have to change f at all.

  7. Remarkable problems that can be solved using this technique are:

    • having a global state that every function in the sequence of functions ("the program") can share: solution StateMonad.

    • We don't like "impure functions": functions that yield different output for same input. Therefore, let's mark those functions, making them to return a tagged/boxed value: IO monad.

Total happiness !!!!


I would say the closest OO analogy to monads is the "command pattern".

In the command pattern you wrap an ordinary statement or expression in a command object. The command object expose an execute method which executes the wrapped statement. So statement are turned into first class objects which can passed around and executed at will. Commands can be composed so you can create a program-object by chaining and nesting command-objects.

The commands are executed by a separate object, the invoker. The benefit of using the command pattern (rather than just execute a series of ordinary statements) is that different invokers can apply different logic to how the commands should be executed.

The command pattern could be used to add (or remove) language features which is not supported by the host language. For example, in a hypothetical OO language without exceptions, you could add exception semantics by exposing "try" and "throw" methods to the commands. When a command calls throw, the invoker backtracks through the list (or tree) of commands until the last "try" call. Conversely, you could remove exception semantic from a language (if you believe exceptions are bad) by catching all exceptions thrown by each individual commands, and turning them into error codes which are then passed to the next command.

Even more fancy execution semantics like transactions, non-deterministic execution or continuations can be implemented like this in a language which doesn't support it natively. It is a pretty powerful pattern if you think about it.

Now in reality the command-patterns is not used as a general language feature like this. The overhead of turning each statement into a separate class would lead to an unbearable amount of boilerplate code. But in principle it can be used to solve the same problems as monads are used to solve in fp.


In terms that an OOP programmer would understand (without any functional programming background), what is a monad?

What problem does it solve and what are the most common places it's used?are the most common places it's used?

In terms of OO programming, a monad is an interface (or more likely a mixin), parameterized by a type, with two methods, return and bind that describe:

  • How to inject a value to get a monadic value of that injected value type;
  • How to use a function that makes a monadic value from a non-monadic one, on a monadic value.

The problem it solves is the same type of problem you'd expect from any interface, namely, "I have a bunch of different classes that do different things, but seem to do those different things in a way that has an underlying similarity. How can I describe that similarity between them, even if the classes themselves aren't really subtypes of anything closer than 'the Object' class itself?"

More specifically, the Monad "interface" is similar to IEnumerator or IIterator in that it takes a type that itself takes a type. The main "point" of Monad though is being able to connect operations based on the interior type, even to the point of having a new "internal type", while keeping - or even enhancing - the information structure of the main class.


You have a recent presentation "Monadologie -- professional help on type anxiety" by Christopher League (July 12th, 2010), which is quite interesting on topics of continuation and monad.
The video going with this (slideshare) presentation is actually available at vimeo.
The Monad part start around 37 minutes in, on this one hour video, and starts with slide 42 of its 58 slide presentation.

It is presented as "the leading design pattern for functional programming", but the language used in the examples is Scala, which is both OOP and functional.
You can read more on Monad in Scala in the blog post "Monads - Another way to abstract computations in Scala", from Debasish Ghosh (March 27, 2008).

A type constructor M is a monad if it supports these operations:

# the return function
def unit[A] (x: A): M[A]

# called "bind" in Haskell 
def flatMap[A,B] (m: M[A]) (f: A => M[B]): M[B]

# Other two can be written in term of the first two:

def map[A,B] (m: M[A]) (f: A => B): M[B] =
  flatMap(m){ x => unit(f(x)) }

def andThen[A,B] (ma: M[A]) (mb: M[B]): M[B] =
  flatMap(ma){ x => mb }

So for instance (in Scala):

  • Option is a monad
    def unit[A] (x: A): Option[A] = Some(x)

    def flatMap[A,B](m:Option[A])(f:A =>Option[B]): Option[B] =
      m match {
       case None => None
       case Some(x) => f(x)
      }
  • List is Monad
    def unit[A] (x: A): List[A] = List(x)

    def flatMap[A,B](m:List[A])(f:A =>List[B]): List[B] =
      m match {
        case Nil => Nil
        case x::xs => f(x) ::: flatMap(xs)(f)
      }

Monad are a big deal in Scala because of convenient syntax built to take advantage of Monad structures:

for comprehension in Scala:

for {
  i <- 1 to 4
  j <- 1 to i
  k <- 1 to j
} yield i*j*k

is translated by the compiler to:

(1 to 4).flatMap { i =>
  (1 to i).flatMap { j =>
    (1 to j).map { k =>
      i*j*k }}}

The key abstraction is the flatMap, which binds the computation through chaining.
Each invocation of flatMap returns the same data structure type (but of different value), that serves as the input to the next command in chain.

In the above snippet, flatMap takes as input a closure (SomeType) => List[AnotherType] and returns a List[AnotherType]. The important point to note is that all flatMaps take the same closure type as input and return the same type as output.

This is what "binds" the computation thread - every item of the sequence in the for-comprehension has to honor this same type constraint.


If you take two operations (that may fail) and pass the result to the third, like:

lookupVenue: String => Option[Venue]
getLoggedInUser: SessionID => Option[User]
reserveTable: (Venue, User) => Option[ConfNo]

but without taking advantage of Monad, you get convoluted OOP-code like:

val user = getLoggedInUser(session)
val confirm =
  if(!user.isDefined) None
  else lookupVenue(name) match {
    case None => None
    case Some(venue) =>
      val confno = reserveTable(venue, user.get)
      if(confno.isDefined)
        mailTo(confno.get, user.get)
      confno
  }

whereas with Monad, you can work with the actual types (Venue, User) like all the operations work, and keep the Option verification stuff hidden, all because of the flatmaps of the for syntax:

val confirm = for {
  venue <- lookupVenue(name)
  user <- getLoggedInUser(session)
  confno <- reserveTable(venue, user)
} yield {
  mailTo(confno, user)
  confno
}

The yield part will only be executed if all three functions have Some[X]; any None would directly be returned to confirm.


So:

Monads allow ordered computation within Functional Programing, that allows us to model sequencing of actions in a nice structured form, somewhat like a DSL.

And the greatest power comes with the ability to compose monads that serve different purposes, into extensible abstractions within an application.

This sequencing and threading of actions by a monad is done by the language compiler that does the transformation through the magic of closures.


By the way, Monad is not only model of computation used in FP:

Category theory proposes many models of computation. Among them

  • the Arrow model of computations
  • the Monad model of computations
  • the Applicative model of computations

To respect fast readers, I start with precise definition first, continue with quick more "plain English" explanation, and then move to examples.

Here is a both concise and precise definition slightly reworded:

A monad (in computer science) is formally a map that:

  • sends every type X of some given programming language to a new type T(X) (called the "type of T-computations with values in X");

  • equipped with a rule for composing two functions of the form f:X->T(Y) and g:Y->T(Z) to a function g∘f:X->T(Z);

  • in a way that is associative in the evident sense and unital with respect to a given unit function called pure_X:X->T(X), to be thought of as taking a value to the pure computation that simply returns that value.

So in simple words, a monad is a rule to pass from any type X to another type T(X), and a rule to pass from two functions f:X->T(Y) and g:Y->T(Z) (that you would like to compose but can't) to a new function h:X->T(Z). Which, however, is not the composition in strict mathematical sense. We are basically "bending" function's composition or re-defining how functions are composed.

Plus, we require the monad's rule of composing to satisfy the "obvious" mathematical axioms:

  • Associativity: Composing f with g and then with h (from outside) should be the same as composing g with h and then with f (from inside).
  • Unital property: Composing f with the identity function on either side should yield f.

Again, in simple words, we can't just go crazy re-defining our function composition as we like:

  • We first need the associativity to be able to compose several functions in a row e.g. f(g(h(k(x))), and not to worry about specifying the order composing function pairs. As the monad rule only prescribes how to compose a pair of functions, without that axiom, we would need to know which pair is composed first and so on. (Note that is different from the commutativity property that f composed with g were the same as g composed with f, which is not required).
  • And second, we need the unital property, which is simply to say that identities compose trivially the way we expect them. So we can safely refactor functions whenever those identities can be extracted.

So again in brief: A monad is the rule of type extension and composing functions satisfying the two axioms -- associativity and unital property.

In practical terms, you want the monad to be implemented for you by the language, compiler or framework that would take care of composing functions for you. So you can focus on writing your function's logic rather than worrying how their execution is implemented.

That is essentially it, in a nutshell.


Being professional mathematician, I prefer to avoid calling h the "composition" of f and g. Because mathematically, it isn't. Calling it the "composition" incorrectly presumes that h is the true mathematical composition, which it isn't. It is not even uniquely determined by f and g. Instead, it is the result of our monad's new "rule of composing" the functions. Which can be totally different from the actual mathematical composition even if the latter exists!


To make it less dry, let me try to illustrate it by example that I am annotating with small sections, so you can skip right to the point.

Exception throwing as Monad examples

Suppose we want to compose two functions:

f: x -> 1 / x
g: y -> 2 * y

But f(0) is not defined, so an exception e is thrown. Then how can you define the compositional value g(f(0))? Throw an exception again, of course! Maybe the same e. Maybe a new updated exception e1.

What precisely happens here? First, we need new exception value(s) (different or same). You can call them nothing or null or whatever but the essence remains the same -- they should be new values, e.g. it should not be a number in our example here. I prefer not to call them null to avoid confusion with how null can be implemented in any specific language. Equally I prefer to avoid nothing because it is often associated with null, which, in principle, is what null should do, however, that principle often gets bended for whatever practical reasons.

What is exception exactly?

This is a trivial matter for any experienced programmer but I'd like to drop few words just to extinguish any worm of confusion:

Exception is an object encapsulating information about how the invalid result of execution occurred.

This can range from throwing away any details and returning a single global value (like NaN or null) or generating a long log list or what exactly happened, send it to a database and replicating all over the distributed data storage layer ;)

The important difference between these two extreme examples of exception is that in the first case there are no side-effects. In the second there are. Which brings us to the (thousand-dollar) question:

Are exceptions allowed in pure functions?

Shorter answer: Yes, but only when they don't lead to side-effects.

Longer answer. To be pure, your function's output must be uniquely determined by its input. So we amend our function f by sending 0 to the new abstract value e that we call exception. We make sure that value e contains no outside information that is not uniquely determined by our input, which is x. So here is an example of exception without side-effect:

e = {
  type: error, 
  message: 'I got error trying to divide 1 by 0'
}

And here is one with side-effect:

e = {
  type: error, 
  message: 'Our committee to decide what is 1/0 is currently away'
}

Actually, it only has side-effects if that message can possibly change in the future. But if it is guaranteed to never change, that value becomes uniquely predictable, and so there is no side-effect.

To make it even sillier. A function returning 42 ever is clearly pure. But if someone crazy decides to make 42 a variable that value might change, the very same function stops being pure under the new conditions.

Note that I am using the object literal notation for simplicity to demonstrate the essence. Unfortunately things are messed-up in languages like JavaScript, where error is not a type that behaves the way we want here with respect to function composition, whereas actual types like null or NaN do not behave this way but rather go through the some artificial and not always intuitive type conversions.

Type extension

As we want to vary the message inside our exception, we are really declaring a new type E for the whole exception object and then That is what the maybe number does, apart from its confusing name, which is to be either of type number or of the new exception type E, so it is really the union number | E of number and E. In particular, it depends on how we want to construct E, which is neither suggested nor reflected in the name maybe number.

What is functional composition?

It is the mathematical operation taking functions f: X -> Y and g: Y -> Z and constructing their composition as function h: X -> Z satisfying h(x) = g(f(x)). The problem with this definition occurs when the result f(x) is not allowed as argument of g.

In mathematics those functions cannot be composed without extra work. The strictly mathematical solution for our above example of f and g is to remove 0 from the set of definition of f. With that new set of definition (new more restrictive type of x), f becomes composable with g.

However, it is not very practical in programming to restrict the set of definition of f like that. Instead, exceptions can be used.

Or as another approach, artificial values are created like NaN, undefined, null, Infinity etc. So you evaluate 1/0 to Infinity and 1/-0 to -Infinity. And then force the new value back into your expression instead of throwing exception. Leading to results you may or may not find predictable:

1/0                // => Infinity
parseInt(Infinity) // => NaN
NaN < 0            // => false
false + 1          // => 1

And we are back to regular numbers ready to move on ;)

JavaScript allows us to keep executing numerical expressions at any costs without throwing errors as in the above example. That means, it also allows to compose functions. Which is exactly what monad is about - it is a rule to compose functions satisfying the axioms as defined at the beginning of this answer.

But is the rule of composing function, arising from JavaScript's implementation for dealing with numerical errors, a monad?

To answer this question, all you need is to check the axioms (left as exercise as not part of the question here;).

Can throwing exception be used to construct a monad?

Indeed, a more useful monad would instead be the rule prescribing that if f throws exception for some x, so does its composition with any g. Plus make the exception E globally unique with only one possible value ever (terminal object in category theory). Now the two axioms are instantly checkable and we get a very useful monad. And the result is what is well-known as the maybe monad.


A monad is a data type that encapsulates a value, and to which, essentially, two operations can be applied:

  • return x creates a value of the monad type that encapsulates x
  • m >>= f (read it as "the bind operator") applies the function f to the value in the monad m

That's what a monad is. There are a few more technicalities, but basically those two operations define a monad. The real question is, "What a monad does?", and that depends on the monad — lists are monads, Maybes are monads, IO operations are monads. All that it means when we say those things are monads is that they have the monad interface of return and >>=.