Monads in small bites  Part IV  Monads
This is Part IV of my Monads tutorial. Make sure you read the previous parts:

Part IV  Monads (this post)
A quick recap
In Part I we learned about Functors, which are things that can be mapped over using a normal function  fmap
is used for that.
Part II tought us that when our Functors themselves contain functions and we want them applied to the values contained in other Functors, Applicatives come to the rescue  and bring theirs friends pure
and <*>
.
Part III introduced Monoids which model a special type of relationship involving binary functions and their identity values.
Now it’s time for what I hope is the post you have all been waiting for :)
Monads
A word on context
So far I’ve said things such as wrapping stuff in Functors, unwrapping functions from Applicatives and putting results into minimal Functors. All this really means is that [Applicative]Functors  and Monads  have associated contexts that model some sort of computation.
For lists, for example, this means they represent computations that can have several results  nondeterminism.
These computations can have much greater implications though  they can represent failure (or not!), do IO and even launch nuclear missiles. The point is: when we combine Functors/Applicatives/Monads, we carry their context with us to the end  they are essentially sequenced together.
This will become clearer with an example. For once I won’t start with lists  w00t!  so get ready for it!
The Maybe Monad
The Maybe monad models computations that can fail. Let’s have a look at an example.
Say you have an ecommerce system. When placing an order, a few things need to get done:
 gather information about the order;
 calculate shipping rates;
 apply discount codes, if any, and;
 finally place the order.
The code below shows the supporting functions that will be orchestrated in order to achieve this:
(defn calculateshippingrate [address]
(if (= (:country address) "Australia")
10.0
nil))
(defn applyshippingcosts [order shippingrate]
(assoc order :total (+ (:total order) shippingrate)))
(defn lookupdiscountcode [code]
(if (= code "XMAS2012")
5.0
nil))
(defn applydiscountcode [order discount]
(assoc order :total ( (:total order) discount)))
(defn place [order]
(prn (str "Off you go! Order total: $" (:total order))))
Note that based on the code above, we can only ship to Australia and there is only one active discount code. Keep this in mind  you’ll see why later on.
Now let’s place an order for some Jalapeño sauce:
(def order {
:items [{:name "Jalapeño sauce" :price 20.0}]
:address {:country "Australia"}
:discountcode "XMAS2012"
:total 20.0
})
(def shippingrate (calculateshippingrate (:address order)))
(def discount (lookupdiscountcode (:discountcode order)))
(> order
(applyshippingcosts shippingrate)
(applydiscountcode discount)
(place))
;; "Off you go! Order total: $25.0"
Great! Soon I’ll be receiving some hot sauce to go with my burritos!
But wait, what if I had mistakenly set my address to somewhere other than Australia? How would this code behave?
(def anotherorder {
:items [{:name "Jalapeño sauce" :price 20.0}]
:address {:country "Brazil"}
:discountcode "HACKERZ"
:total 20.0
})
(def shippingrate (calculateshippingrate (:address anotherorder)))
(def discount (lookupdiscountcode (:discountcode anotherorder)))
(> anotherorder
(applyshippingcosts shippingrate)
(applydiscountcode discount)
(place))
;; NullPointerException [trace missing]
Oops! Your ecommerce system just crashed! Not cool. But hey, this is easy to fix, right? We could just change our applyshippingcosts function to something like this:
(defn applyshippingcosts [order shippingrate]
(if shippingrate
(assoc order :total (+ (:total order) shippingrate))
order))
;;Remember we only support one discount code so the same problem could happen again
;;We need to change the applydiscountcode function as well
(defn applydiscountcode [order discount]
(if discount
(assoc order :total ( (:total order) discount))
order))
Now let’s see what happens:
(def shippingrate (calculateshippingrate (:address anotherorder)))
(def discount (lookupdiscountcode (:discountcode anotherorder)))
(> anotherorder
(applyshippingcosts shippingrate)
(applydiscountcode discount)
(place))
;; "Off you go! Order total: $15.0"
Well, it doesn’t crash but we can’t ship to Brazil anyway! So the code is still incorrect! What we really want is a way to halt the whole computation  placing an order  if any of those steps fail.
Of course we could fix it with a couple more if forms before trying to call the place function but you see where this is going.
Essentially our nice little functions became burdened with context: each of them is now aware that they can fail and need to cater for it.
Enter the Monad
I’ll jump straight to how the code could look like if we had monads  it won’t work now because we haven’t actually implemented the monad yet, but this should whet your appetite.
Also, assume we reversed the changes from before  the functions don’t have the if forms checking its arguments any longer, just like in the original version. Here’s the code:
(domonad maybemonad
[order order
shippingrate (calculateshippingrate (:address order))
discount (lookupdiscountcode (:discountcode order))]
(> order
(applyshippingcosts shippingrate)
(applydiscountcode discount)
(place)))
;;"Off you go! Order total: $25.0"
(domonad maybemonad
[order anotherorder
shippingrate (calculateshippingrate (:address order))
discount (lookupdiscountcode (:discountcode order))]
(> order
(applyshippingcosts shippingrate)
(applydiscountcode discount)
(place)))
;; nil
domonad
receives the monad you want to operate on, a vector of bindings and an expression that’s the final result of the whole thing.
Is your mind blown yet? :) Somehow the whole operation fails and yields nil
in the second call to domonad above  without any if forms and without crashing! To see why that is, I’ll now explain the monad type class from Haskell.
The Monad Type Class
Here’s the Haskell definition of the Monad type class (I left the fail
function out so we can focus on the core of it):
class Monad m where
return :: a > m a
(>>=) :: m a > (a > m b) > m b
(>>) :: m a > m b > m b
x >> y = x >>= \_ > y
Let’s distill those bad ass type signatures:
return  much like
pure
from Applicative Functors,return
is responsible for wrapping a value of typea
into a minimum context Monad that yields a value of typea
 referred to as a monadic value.
(»=)  often called
bind
 is a function of two arguments. The first is a monadic value of typea
and the second is a function that receives a value of typea
and returns a monadic value of typem b
which is also the overall result of the function.
In other words:
bind
runs the monadm a
, feeding the yieldeda
value into the function it received as an argument  any context carried by that monad will be taken into account.
(»)  often called
then
 This function receives two monads,m a
andm b
, and returns a monad of typem b
. It is generally used when you’re interested in the side effects  the context  carried out by the monadm a
but doesn’t care about the valuea
it yields. It’s rarely implemented in specific monads because the type class provides a default implementation:
It applies
bind
to the monadx
and a function that ignores its argument (\_ > y
)  which by convention is represented by an underscore  and simply yields the monady
: that’s the final result of the computation.
I won’t be implementing then
in Clojure though  I’ll focus on return
and bind
, since then
is essentially a helper function you could write yourself.
The Maybe Monad  Clojure edition
With definitions out of the way, let’s implement the Clojure version of the Maybe monad.
(def maybemonad {
:return (fn [v] v)
:bind (fn [mv f]
(if mv
(f mv)
nil))})
Yup. That’s it.
For the maybe monad, all its context needs to represent is a single value or the absence of value. We do this inside bind
by checking if the monadic value mv
is nil
. If it isn’t, we apply f
to it, which will yield another monadic value. If, on the other hand, mv
IS nil
, we just return nil
, bypassing the function application entirely.
return
, as we saw, wraps a value into a minimal monad. In this case this is the value itself, so we just return it untouched.
This is how one may go about using it:
(> anotherorder
((:bind maybemonad)
(fn [order]
(> (calculateshippingrate (:address order))
((:bind maybemonad)
(fn [shippingrate]
(> (lookupdiscountcode (:discountcode order))
((:bind maybemonad)
(fn [discount]
((:return maybemonad)
(> order
(applyshippingcosts shippingrate) (
applydiscountcode discount)
(place))))))))))))
;; nil
WOW! That is awful! And I won’t blame you for not wanting to read through this aberration. But trust me, it does the job.
However, you’re probably thinking: that looks nothing like the nice little domonad
notation we saw earlier!
Well, you’re right. That’s because domonad
is a macro  it gives us some syntactic sugar that expands into the real code shown above. In order to be able to use the domonad
notation, paste the following into your REPL:
(defn monadsteps
([monad steps expr]
(if (seq steps)
(let [fst (first steps)
snd (second steps)]
`((:bind ~monad)
(fn [~(symbol fst)]
(> ~snd ~(monadsteps monad (subvec steps 2) expr)))))
expr)))
(defmacro domonad [monad steps expr]
(let [args (map first (partition 2 steps))
forms (map second (partition 2 steps))
newsteps (subvec (vec (interleave (cons nil args) forms)) 2)]
`(let [m# ~monad]
(> ~(second steps)
~(monadsteps monad newsteps
`((:bind ~monad) (fn [~(symbol (last args))] ((:return ~monad) ~expr))))))))
All set! Now you should be able to run the examples that use domonad
without any hiccups. Give it a shot:
(domonad maybemonad
[order anotherorder
shippingrate (calculateshippingrate (:address order))
discount (lookupdiscountcode (:discountcode order))]
(> order
(applyshippingcosts shippingrate)
(applydiscountcode discount)
(place)))
;; nil
Note: macros can be daunting at times so don’t worry too much about its implementation. It’s way more important to me that you understand the end result than it is to be able to implement the macro yourself  but by all means dissect this implementation if you feel inclined to do so :)
Now that’s way better. The maybe monad abstracted away the logic behind computations that can fail so you don’t have to worry about it in your functions  you can just focus on writing them.
In the end I also believe it aids readability once you get used to it.
Don’t break the law
Monads have laws of their own too! Let’s have a look at them.
Right unit
Binding a monadic value
m
toreturn
should be equal tom
itself
In Haskell speak:
m >>= return = m
The proof in Clojure:
(def m 10)
(def >>= (:bind maybemonad))
(def return (:return maybemonad))
;; given the above, this...
(>>= m return) ;; 10
;;is the same as
m ;; 10
Left unit
Applying
return
tox
and then applying>>=
to the resulting value andf
should be the same as applyingf
directly tox
In Haskell speak:
return x >>= f = f x
The proof in Clojure:
(def x 10)
(def >>= (:bind maybemonad))
(def return (:return maybemonad))
(def f (fn [v] (* v 2)))
;; given the above, this...
(> (return x) (>>= f)) ;; 20
;;is the same as
(f x) ;; 20
Associativity
Binding
m
tof
and then applying>>=
to the result andg
should be the same as applying>>=
tom
and a function of argumentx
that first appliesf
tox
and then binds it tog
.
Phew…another mouthful, huh? Code should make it clearer. As usual, Haskell comes first:
(m >>= f) >>= g = m >>= (\x > f x >>= g)
And now let’s prove it in Clojure:
(def >>= (:bind maybemonad))
(def return (:return maybemonad))
(def m 10)
(def f (fn [v] (* v 2)))
(def g (fn [v] (+ v 10)))
;; given the above, this...
(> (>>= m f) (>>= g)) ;; 30
;;is the same as
(>>= m
(fn [x]
(>>= (f x) g))) ;; 30
Alright, we’re getting to the end now! Hold on just a little longer!
One last thing  The List Monad
Yeah, I’m sure you saw this coming. Lists are monads too! I’ll make this quick and show its implementation and usage in Clojure  bear with me one last time.
(def listmonad {
:return (fn [v] [v])
:bind (fn [mv f]
(if (seq mv)
(apply concat (map f mv))
[]))
})
;;let's play with it
(domonad listmonad
[a [1 2]
b [a, ( a)]]
(* 3 b))
;; (3 3 6 6)
(domonad listmonad
[a [1 2]
b []]
(* 3 b))
;; ()  an empty list.
This should look familiar if you’ve used list comprehensions in Clojure or other languages such as Python:
(for [a [1 2]
b [a, ( a)]]
(* 3 b))
;; (3 3 6 6)
See? You’ve been using monads all along and didn’t even know it! How awesome is that?
Also note that we didn’t need to reimplement domonad
for the list monad. It’s a generic macro that will work with any monads you throw at it!
It’s interesting to see how the list and the maybe monads differ. This time, return
puts the value v
inside a list and returns it because for lists, a minimum monad is a list with a single element.
bind
is a bit more interesting. It first checks to see if mv
is empty, in which case it returns an empty list, causing the whole computation to stop. If, however, mv
is NOT empty, it maps f
over every element in mv
.
The resulting list is potentially a list of lists, since functions fed to monads  such as f
in this case  have to return monadic values. That’s why we then apply concat
to the resulting list, effectively flattening it.
Final words
Hopefully you now have a much better understanding of Monads and should start seeing in your code use cases and/or opportunities for the monads shown here.
You’ll notice that this Clojure implementation of monads used only normal functions  that was by design since I wanted this implementation to be as close as possible to Clojure’s core.algo.monads library. You should have a look at it.
Also, bear in mind that this tutorial is by no means exhaustive  there’s a lot more about monads that I could possibly cover in a blog  it was hard enough ending it here! But if you want to study more about them, I’d recommend starting with these resources:

Learn You a Haskell for Great Good  this book is an excellent intro to Haskell and it was the approach found there that made me grok monads  highly recommended and freely available online.

The Monads Section on the Haskell wikibook  another free online resource
That’s it from me. I hope you enjoyed the read and if you made it until here, a big thank you.