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
Yes,
mzerois capable of returning somem awherea /= (). But it's also capable of returningm ().guarduses it in this second case.It's similar to this:
5can be aFloatorDouble, but can also be anInt. The compiler chooses the needed interpretation of5during type checking.Similarly, the compiler chooses the right type for
mzeroin the original example during type checking. More precisely, it sees that am ()is needed, so it chooses that type.The important bit here is that
actually means
which states that the caller of
mzerogets to choose the actual values formanda(as long asmis aMonadPlus). Hence, the caller can choosea=()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.