guard :: (MonadPlus m) => Bool -> m ()
guard True = return ()
guard False = mzero
Prelude Control.Monad> :t mzero
mzero :: (MonadPlus m) => m a
在guard
的假分支中,mzero
的类型为m a
,但guard
的返回类型已指定为m ()
。因此我不太明白为什么编译器不会抱怨这个。
我的意思是,如果mzero
返回一个类型为Maybe Int
的值,这当然与Maybe ()
不同,对吗?
答案 0 :(得分:6)
编译器不会抱怨,因为m a
是m ()
的超集。
答案 1 :(得分:0)
mzero :: (MonadPlus m) => m a
的类型对于forall (a :: *) (m :: * -> *). MonadPlus m => m a
来说有点简短,这意味着任何选择类型构造函数m
并输入a
},如果仅满足m
是MonadPlus
类型类的实例的限制,则mzero
可以是该类型。
guard
的类型同样为forall (m :: * -> *). MonadPlus m => Bool -> m ()
。在guard False = mzero
中,右侧的mzero
类型必须为m ()
才能选择m
。选择a
为()
和m
作为请求的monad,mzero
的类型,其本身就变为m ()
,这正是guard
{1}}需要返回。