aXqd
aXqd

Reputation: 743

'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?

Upvotes: 2

Views: 235

Answers (2)

Cactus
Cactus

Reputation: 27636

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.

Upvotes: 0

kennytm
kennytm

Reputation: 523574

The compiler won't complain because m a is a superset of m ().

Upvotes: 6

Related Questions