MonadPlus
and Monoid
服务于不同的目的。
A Monoid
通过 kind 的类型进行参数化*
.
class Monoid m where
mempty :: m
mappend :: m -> m -> m
因此它可以被实例化为几乎任何类型,只要有一个明显的结合运算符并且有一个单位。
然而,MonadPlus
不仅指定您具有幺半群结构,而且还指定该结构与Monad
works, and该结构不关心 monad 中包含的值,这一点(部分)由以下事实表明:MonadPlus
进行某种争论* -> *
.
class Monad m => MonadPlus m where
mzero :: m a
mplus :: m a -> m a -> m a
除了幺半群定律之外,我们还有两套潜在的定律可以应用到MonadPlus
。可悲的是,社区对于它们应该是什么样子存在不同意见。
至少我们知道
mzero >>= k = mzero
但还有另外两个相互竞争的扩展,左(原文如此)分布定律
mplus a b >>= k = mplus (a >>= k) (b >>= k)
和左捕获法则
mplus (return a) b = return a
所以任何实例MonadPlus
应满足这些附加法律中的一项或两项。
那么呢Alternative
?
Applicative
是在之后定义的Monad
,并且逻辑上属于Monad
,但很大程度上是由于 Haskell 98 中设计师面临的不同压力,甚至Functor
不是一个超类Monad
直到2015年。现在我们终于有了Applicative
作为一个超类Monad
在 GHC 中(如果尚未在语言标准中。)
有效地,Alternative
is to Applicative
what MonadPlus
is to Monad
.
对于这些我们会得到
empty <*> m = empty
类似于我们所拥有的MonadPlus
并且存在类似的分配和捕获属性,您至少应该满足其中之一。
不幸的是,即使empty <*> m = empty
法律的主张过于强烈。它不适用向后, 例如!
当我们观察 MonadPlus 时,空 >>= f = 空法则几乎是强加给我们的。空结构中不能有任何“a”来调用该函数f
无论如何。
然而,自从Applicative
is not的超类Monad
and Alternative
is not的超类MonadPlus
,我们最终分别定义两个实例。
而且,即使Applicative
是一个超类Monad
,你最终会需要MonadPlus
无论如何都要上课,因为即使我们确实遵守了
empty <*> m = empty
这还不足以证明这一点
empty >>= f = empty
所以声称某物是MonadPlus
比声称的更强大Alternative
.
现在,按照惯例,MonadPlus
and Alternative
对于给定类型应该一致,但是Monoid
may be 完全地不同的。
例如MonadPlus
and Alternative
for Maybe
做显而易见的事情:
instance MonadPlus Maybe where
mzero = Nothing
mplus (Just a) _ = Just a
mplus _ mb = mb
but the Monoid
实例将半群提升为Monoid
。可悲的是,因为不存在Semigroup
当时在 Haskell 98 中,它通过要求Monoid
,但不使用其单位。 ಠ_ಠ
instance Monoid a => Monoid (Maybe a) where
mempty = Nothing
mappend (Just a) (Just b) = Just (mappend a b)
mappend Nothing x = x
mappend x Nothing = x
mappend Nothing Nothing = Nothing
TL;DR MonadPlus
是一个比Alternative
,这又是一个比Monoid
,而同时MonadPlus
and Alternative
类型的实例应该是相关的,Monoid
可能(有时是)完全不同的东西。