So far, we’ve looked at two similar but different monads, set-m and sequence-m. We’ve seen they both have an m-result and an m-bind function, as do all monads. What we glossed over is just how those functions define a monad. So here’s a simple definition of a monad:
A monad is composed of two functions, m-result and m-bind, that obey the 3 monad laws.
An underlying idea is that monad involves putting values into a container data structure to create monadic values. And providing monadic functions, which accept any value and return monadic values. Since m-result takes any value and returns a monadic value, it is the simplest monadic function. And m-bind is used to extract a value from inside a monadic value, apply a monadic function to it and then removing any nesting of containers to produce a flattened monadic value.
With that said, let’s look at the 3 monad laws.
The first Monad Law can be written as
(m-bind (m-result x) f) is equal to (f x)
What this means is that whatever m-result does to x to make it into a monadic value, m-bind undoes before applying f to x. So with regards to m-bind, m-result is sort of like an identity function. Or in category theory terminology, its unit. Which is why sometimes you’ll see it named ‘unit’.
The second Monad Law can be written as
(m-bind mv m-result) is equal to mv
where mv is a monadic value. This law is something like a complement to the first law. It basically ensures that m-result is a monadic function and that whatever m-bind does to a monadic value to extract a value, m-result undoes to create a monadic value.
The third Monad Law can be written as
(m-bind (m-bind mv f) g) is equal to (m-bind mv (fn [x] (m-bind (f x) g)))
where f and g are monadic functions and mv is a monadic value. What this law is saying is that it doesnt matter whether the f is applied to mv and then g is applied to the result, or whether a new monadic function is created out of a composition of f and g which is then applied to mv. In either order, the resulting value is the same monadic value. Stated another way, m-bind is left and right associative.
Any function that is written in terms of m-result and m-bind will be correct for any monad, which is kind of cool. You can write some code and test it. Then later you can tweak the monad and know that your original function is still correct.
Most of the time, you don’t need to worry about the monad laws because you’ll use the common monads that are already defined. But if you ever decide to create your own monad, the first thing you should do is make sure your m-result and m-bind adhere to these laws. It’ll save you a lot of time and agony.
Next time, a better notation for compositions.Tweet Jim Duey 06 February 2012