I describe four sources of information you can use to learn about the behavior of >>=
for specific monads.
The type of >>=
The type of >>=
is always the same. It is specified in the Monad
type class. See documentation. The type is:
(>>=) :: forall a b. m a -> (a -> m b) -> m b
Where m
is a placeholder for the specific monad you are interested in. For example, for the list monad, the type of >>=
is:
(>>=) :: forall a b. [a] -> (a -> [b]) -> [b]
Note that I just replaced m ...
by [...]
.
The monad laws
The implementation of >>=
is different for every monad, but all monads are supposed to keep to the monad laws. These laws are specified in the documentation of the Monad
type class. See documentation again. The laws are:
return a >>= k == k a
m >>= return == m
m >>= (\x -> k x >>= h) == (m >>= k) >>= h
So whatever the implementation of some specific monad might be, you can use these laws to reason about your code. For example, if your code contains code like on the left-hand side of a law, you can replace that code by the corresponding right-hand side of the law, and the behavior should not change.
Here is an example for how to use a monad law. Assume I wrote this code:
foo = do
x <- bar
return x
We don't even know what monad is used here, but we know there's some monad, because we see the do notation. To apply the monad law, we have to desugar the do notation to calls of >>=
:
foo = bar >>= (\x -> return x)
Note that \x -> return x
is the same as just return
(by η-reduction.
foo = bar >>= return
By the second monad law, this code means the exact same thing as just calling bar.
foo = bar
So it looks as if the >>=
in the original foo
function cannot do anything interesting at all, because the monad laws allow us to just leave it out. We figured that out without even knowing what specific monad supplies the >>=
operator here.
The documentation of a specific monad
If you need to know more about the behavior of >>=
for a specific monad, the documentation of the specific monad should tell you. You can use hoogle to search for the documentation. For example, the documentation of StateT
tells you:
The return
function leaves the state unchanged, while >>=
uses the final state of the first computation as the initial state of the second.
The implementation of a specific monad
If you want to know more details about the implementation of a specific monad, you probably have to look at the actual implementation. Search for the instance Monad ...
declaration. For example, look at the implementation of StateT
. The implementation of the list monad is somewhere in this file, search for instance Monad []
or look at this except:
instance Monad [] where
m >>= k = foldr ((++) . k) [] m
m >> k = foldr ((++) . (\ _ -> k)) [] m
return x = [x]
fail _ = []
Maybe not the most obvious definition, but that's exactly what happens if you call >>=
for the list monad.
Summary
All monads share the type signatures for >>=
and return
and the monad laws. Aparat from these constraints, every monad provides a different implementation of >>=
and return
, and if you want to know all the details, you'll have to study the source code of the instance Monad ...
declaration. If you just want to learn how to use a specific monad, try finding some documentation about that.
head
and monad functions like(>>=)
. (Sometimes you actually can provide a single valid implementation given a type signature, and there is a tool that does this, but it's probably beyond your level of theory at the moment.) – kqr