This is the signature of the well know >>= operator in Haskell
>>= :: Monad m => m a -> (a -> m b) -> m b
The question is why
The reason is that (>>=)
is more general. The function you're suggesting is called liftM and can be easily defined as
liftM :: (Monad m) => (a -> b) -> (m a -> m b)
liftM f k = k >>= return . f
This concept has its own type class called Functor
with fmap :: (Functor m) => (a -> b) -> (m a -> m b)
. Every Monad
is also a Functor
with fmap = liftM
, but for historical reasons this isn't (yet) captured in the type-class hierarchy.
And adapt
you're suggesting can be defined as
adapt :: (Monad m) => (a -> b) -> (a -> m b)
adapt f = return . f
Notice that having adapt
is equivalent to having return
as return
can be defined as adapt id
.
So anything that has >>=
can also have these two functions, but not vice versa. There are structures that are Functors but not Monads.
The intuition behind this difference is simple: A computation within a monad can depend on the results of the previous monads. The important piece is (a -> m b)
which means that not just b
, but also its "effect" m b
can depend on a
. For example, we can have
import Control.Monad
mIfThenElse :: (Monad m) => m Bool -> m a -> m a -> m a
mIfThenElse p t f = p >>= \x -> if x then t else f
but it's not possible to define this function with just Functor m
constraint, using just fmap
. Functors only allow us to change the value "inside", but we can't take it "out" to decide what action to take.