'm a' vs 'm ()' in guard
guard :: (MonadPlus m) => Bool开发者_开发知识库 -> m ()
guard True = return ()
guard False = mzero
Prelude Control.Monad> :t mzero
mzero :: (MonadPlus m) => m a
In the False branch of guard
, the type of mzero
is m a
, but the return type of guard
has been specified as m ()
. Hence I don't quite get it why compiler won't complain about this.
I mean if mzero
returns a value typed as Maybe Int
, which is, of course, different from Maybe ()
, right?
The compiler won't complain because m a
is a superset of m ()
.
The type of mzero :: (MonadPlus m) => m a
is a bit of short-hand for forall (a :: *) (m :: * -> *). MonadPlus m => m a
, meaning for any choice of type constructor m
and type a
, if just the restriction that m
is an instance of the MonadPlus
typeclass is satisfied, mzero
can be at that type.
The type of guard
, similarly, is forall (m :: * -> *). MonadPlus m => Bool -> m ()
. In guard False = mzero
, the type of the mzero
on the right-hand side must thus be m ()
for any appropriate choice of m
. By choosing a
to be ()
and m
to be the requested monad, mzero
's type, itself becomes m ()
which is exactly what guard
needs to return.
精彩评论