I’m mostly a practical guy but I find this interesting.
I have been thinking about monadic sequencing and there are a few
things that I need clarified. So at the risk of sounding silly here
it is:
The monadic member bind
bind :: m b -> (b -> m c) -> m c
can sequence “actions” giving you explicit access to intermediate values.
How does this give me more than the categorical member (.):
(.) :: cat b c -> cat a b -> cat a c
With this I can sequence and get access to intermediate values.
After all (f . g) x = f(g (x)).
Why do I need bind for sequencing if I can sequence with (.)?
You’re on the right track. Every monad gives rise to so-called Kleisli category. For every monad
mits corresponding Kleisli category has arrowsa -> m band they can be composed using >=>, which is defined asKleisli type encapsulates this in Haskell type system, you can see that it has instance
So sequencing computations within this category is just sequencing operations using
>=>, which can be expressed equivalently using>>=.We define monads using
returnand>>=because it’s more convenient, but we could define them as well usingreturnand>=>if we wanted.(See also my answer to Different ways to see a monad.)