haskellmonadsalternative-functormonadplus

How does mzero match guard type signature?


I have trouble understanding how guard works. Why does it type check? Isn't mzero capable of returning some m a where a /= ()?

guard           :: (MonadPlus m) => Bool -> m ()
guard True      =  return ()
guard False     =  mzero

mzero :: m a 

Solution

  • Yes, mzero is capable of returning some m a where a /= (). But it's also capable of returning m (). guard uses it in this second case.

    It's similar to this:

    n :: Int
    n = 5
    

    5 can be a Float or Double, but can also be an Int. The compiler chooses the needed interpretation of 5 during type checking.

    Similarly, the compiler chooses the right type for mzero in the original example during type checking. More precisely, it sees that a m () is needed, so it chooses that type.

    The important bit here is that

    mzero :: MonadPlus m => m a
    

    actually means

    mzero :: forall m a . MonadPlus m => m a
    

    which states that the caller of mzero gets to choose the actual values for m and a (as long as m is a MonadPlus). Hence, the caller can choose a=() to make things type check. This choice can be made by the user through a type annotation, otherwise the compiler will try to infer the correct choice during type checking.