Monads Are Just Fancy Semicolons

Monads can be scary — treating them like fancy semicolons makes them fun!

Marcel Moosbrugger
Feb 3 · 5 min read
Image by Marcel Moosbrugger

Monads are programmable semicolons. That’s it. For a programmer, a monad provides functions that allow for sequencing actions. Moreover, between every two following actions, a specific code snippet is executed.

So, a monad is a semicolon — but one whose exact behavior you can configure.


Let’s Take a Step Back and Start Slow

Nice to know: Monads originate from a mathematical field called “Category Theory.” For using and understanding monads in Haskell it’s not necessary to know the definitions and theorems of this mathematical discipline.

So, if sequencing is easier to do in other languages, is Haskell badly designed?

No, not at all. One could say, that it was intentional that sequencing was more difficult. Haskell was designed to be referentially transparent, which is just a fancy way of saying that each function call can be replaced with its return value.

Imagine you have a function named doCalculation which takes a number, does some calculation and returns a number. In Haskell, the expression doCalculation(x) + doCalculation(x) can be replaced with 2 * doCalculation(x) and we can be sure that the behavior of the program won’t change. In Java, in general this replacement can’t be done in general, as it’s not assured that doCalculation returns the same result on every call. For example, the method could just call a random number generator and always return a different result. Also, in languages like Java doCalculation could include common side-effects like writing to a database or log out to the console.

Referential transparency comes with a lot of advantages. Optimizations are easier for compilers of referential transparent languages. Moreover, parallelism can be automated to some degree. However, all these features come with the cost of more difficult sequencing. But for that matter, we can make use of monads.

Let’s make ourselves a monad

To begin with, we have to define a new type:

The type Counter consists of an integer named counter and an arbitrary element. For our shopping lists, the element will be a list of strings. The counter will represent the number of manipulations done to that list.

Let’s get to the important part. To program our semicolon, enabling sequencing, we do the following:

This is where all the magic happens. To begin with the more straightforward function, return just constructs a new Counter for a given element. It can be used to construct a new Counter starting with 0 manipulations for a given shopping list.

>>= is the “programmable semicolon”. As with everything in Haskell, it’s just another function. In our example it is of type Counter a -> (a -> Counter b) -> Counter b (for our concrete shopping lists, a and b will both be lists of strings).

Let’s go slowly.

>>= gets a Counter with an element (called x in the code). It manipulates the element with a given function, which again returns a Counter. Finally, >>= returns a new Counter, in which the integer representing the number of manipulations is the integer of the given Counter plus the integer of the Counter returned by the given function plus 1.

What’s crucial in the definition of our programmable semicolon is that the Counter is known before the function, given in the second argument, can be evaluated. So, if the Counter in the first argument (which comes before >>=) is just an expression resulting in a concrete Counter, we can be sure that this expression will be evaluated before the function given in the second argument (which comes after >>=) is called.

For the ability to add items to our shopping lists as well as remove them, we need to define two more functions, which are both one-liners. Moreover, we define our first shopping list — namely the empty shopping list.

At this point, we have everything at hand to create a typical shopping list, one item at a time.

Executing the code leads to the following output:

What’s happening here?

We begin with the empty shopping list, which has no elements in it and has its counter initialized to 0. Our programmable semicolon, >>=, takes the list resulting from a line and passes it to the function in the next line.

The empty shopping list is essentially handed through the lines and manipulated at each stage. The central point is that we can be sure that, for example, “Bread” is added before “Butter.” As described above, that’s thanks to the definition of our programmable semicolon.

But notice how everything in our (as it’s called) “monadic action” is made up of functions. Each line is an anonymous function (except the first), as well as >>=. In conclusion, we’ve implemented a way to sequence actions in a purely functional way.

Haskell provides a lot of syntactic sugar, which allows for writing the monadic action above in a way that emphasizes the sequential property more:

The two definitions are completely equivalent. In the end, it’s a matter of taste which one to use. To begin with, though, it’s advisable to use the explicit form, to be reminded of what’s going on behind the scenes.

One more important fact about the counting of manipulation. Once defined in the programmable semicolon, the counting is completely invisible within the monadic action. The magic happens inside our semicolon, >>=. As the functionality of this function can be freely defined, it’s a great place to hide all sorts of things. The predefined maybe monad, for example, hides checking for null in its programmable semicolon and skips all following lines if null occurs. Moreover, logging can be implemented in a monadic way and hidden in >>=. Parsers are another application, which makes use of the state monad — but that’s a whole other story.

So, monads are useful in a variety of scenarios. In the end they’re nothing more and nothing less than programmable semicolons.

Better Programming

Advice for programmers.

Thanks to Zack Shapiro

Marcel Moosbrugger

Written by

I am a computer science researcher, enjoying to explain complex things in simple terms || linkedin.com/in/marcel-moosbrugger

Better Programming

Advice for programmers.

Welcome to a place where words matter. On Medium, smart voices and original ideas take center stage - with no ads in sight. Watch
Follow all the topics you care about, and we’ll deliver the best stories for you to your homepage and inbox. Explore
Get unlimited access to the best stories on Medium — and support writers while you’re at it. Just $5/month. Upgrade