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 m
its corresponding Kleisli category has arrows a -> m b
and they can be composed using >=>, which is defined as
f >=> g = \x -> f x >>= g
Kleisli type encapsulates this in Haskell type system, you can see that it has instance
instance Monad m => Category (Kleisli m) where
id = Kleisli return
(Kleisli f) . (Kleisli g) = Kleisli (g >=> f)
So sequencing computations within this category is just sequencing operations using >=>
, which can be expressed equivalently using >>=
.
We define monads using return
and >>=
because it's more convenient, but we could define them as well using return
and >=>
if we wanted.
(See also my answer to Different ways to see a monad.)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With