Many of us don\'t have a background on functional programming, and much less on category theory algebra. So let\'s suppose that we need and therefore create a generic type like<
A big step forward for me in my understanding of monads was the post Monads are Trees with Grafting. If your type looks like a tree, and the t
values appear at the leaves, then you may have a monad on your hands.
Some data types are obviously trees, for example the Maybe
type
data Maybe a = Nothing | Just a
which either has a null leaf, or a leaf with a single value. The list is another obvious tree type
data List a = Nil | Cons a (List a)
which is either a null leaf, or a leaf with a single value and another list. An even more obvious tree is the binary tree
data Tree a = Leaf a | Bin (Tree a) (Tree a)
with values at the leaves.
However, some types don't look like trees at first glance. For example, the 'reader' monad (aka function monad or environment monad) looks like
data Reader r a = Reader { runReader :: r -> a }
Doesn't look like a tree at the moment. But let's specialize to a concrete type r
, for example Bool
--
data ReaderBool a = ReaderBool (Bool -> a)
A function from Bool
to a
is equivalent to a pair (a,a)
where the left element of the pair is the value of the function on True
and the right argument is the value on False
--
data ReaderBool a = ReaderBool a a
which looks a lot more like a tree with only one type of leaf - and indeed, you can make it into a monad
instance Monad ReaderBool where
return a = ReaderBool a a
ReaderBool a b >>= f = ReaderBool a' b'
where
ReaderBool a' _ = f a
ReaderBool _ b' = f b
The moral is that a function r -> a
can be viewed as a big long tuple containing many values of type a
, one for each possible input - and that tuple can be viewed as the leaf of a particularly simple tree.
The state monad is another example of this type
data State s a = State { runState :: s -> (a, s) }
where you can view s -> (a, s)
as a big tuple of values of type (a, s)
-- one for possible input of type s
.
One more example - a simplified IO action monad
data Action a = Put String (Action a)
| Get (String -> Action a)
| Return a
This is a tree with three types of leaf -- the Put
leaf which just carries another action, the Get
leaf, which can be viewed as an infinite tuple of actions (one for each possible String
input) and a simple Return
leaf that just carries a single value of type a
. So it looks like it might be a monad, and indeed it is
instance Monad Action where
return = Return
Put s a >>= f = Put s (a >>= f)
Get g >>= f = Get (\s -> g s >>= f)
Return a >>= f = f a
Hopefully that's given you a little bit of intuition.
Thinking of monads as trees, the return
operation as a way of getting a simple tree with one value, and the >>=
operation as a way replacing the elements at the leaves of the tree with new trees, can be a powerful unifying way to look at monads.