On the signature of >>= Monad operator

后端 未结 6 2334
粉色の甜心
粉色の甜心 2021-02-14 13:54

This is the signature of the well know >>= operator in Haskell

>>= :: Monad m => m a -> (a -> m b) -> m b

The question is why

6条回答
  •  臣服心动
    2021-02-14 14:22

    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.

提交回复
热议问题