A few footnotes to Lee's answer:
However, the bind
function looks pretty weird. Why are f
and g
nested the other way around?
Because bind
is backwards. Compare (>>=)
and its flipped version (=<<)
:
(>>=) :: Monad m => m a -> (a -> m b) -> m b
(=<<) :: Monad m => (a -> m b) -> m a -> m b
Or, in your specific example:
(>>=) :: (r -> a) -> (a -> (r -> b)) -> (r -> b)
(=<<) :: (a -> (r -> b)) -> (r -> a) -> (r -> b)
While in practice we tend to use (>>=)
more often than (=<<)
(because of how (>>=)
, syntactically speaking, lends itself well to the kind of pipeline monads are often used to build), from a theoretical point of view (=<<)
is the most natural way of writing it. In particular, the parallels and differences with fmap
/(<$>)
and (<*>)
are much more obvious:
(<$>) :: Functor f => (a -> b) -> f a -> f b
(<*>) :: Applicative f => f (a -> b) -> f a -> f b
(=<<) :: Monad f => (a -> f b) -> f a -> f b
When I apply apply
/bind
with an unary and a binary function, they yield the same result. This doesn't make much sense.
That is an accidental fact about the function instances. Let's put the specialised signatures side by side:
(<*>) :: (r -> (a -> b)) -> (r -> a) -> (r -> b)
(=<<) :: (a -> (r -> b)) -> (r -> a) -> (r -> b)
Monad
goes beyond Applicative
by providing the means to determine the next effect according to previous results (as opposed to "previous effect" -- Applicative
can do that already). The effect, in this case, consists of a function that generates values given an argument of type r
. Now, since functions with multiple arguments (i.e. functions that return functions) can be flipped, it happens that there is no significant difference between (r -> (a -> b))
and (a -> (r -> b))
(flip
can trivially change one into the other), which makes the Monad
instance for (->) r
entirely equivalent to the Applicative
one.
与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…