MonadPlus
并Monoid
服务于不同的目的。
AMonoid
在 kind 类型上被参数化*
。
class Monoid m where
mempty :: m
mappend :: m -> m -> m
因此它可以被实例化为几乎任何有明显的关联运算符并且具有单元的类型。
然而,MonadPlus
不仅指定你有一个monoidal结构,而且该结构与Monad
工作方式有关,并且该结构不关心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 中设计人员面临的不同压力,甚至直到 2015Functor
年才成为超类Monad
。现在我们终于有了GHCApplicative
中的超类(如果不是Monad
但在语言标准中。)
实际上,Alternative
是Applicative
什么MonadPlus
是什么Monad
。
对于这些我们会得到
empty <*> m = empty
类似于我们所拥有的,MonadPlus
并且存在类似的分配和捕获属性,至少您应该满足其中一个。
不幸的是,即使是empty <*> m = empty
法律的要求也太强了。例如,它不适用于Backwards!
当我们查看 MonadPlus 时,empty >>= f = empty 定律几乎是强加给我们的。无论如何,空结构中不能有任何'a'来调用函数f
。
但是,由于Applicative
不是的超类,也不是的超类,我们最终分别定义了这两个实例。Monad
Alternative
MonadPlus
此外,即使Applicative
是 的超类Monad
,你最终还是需要这个MonadPlus
类,因为即使我们确实服从
empty <*> m = empty
这还不足以证明
empty >>= f = empty
因此,声称某物是 aMonadPlus
比声称它是 强Alternative
。
现在,按照惯例,给定类型的 and 应该是一致的,但MonadPlus
可能完全不同。Alternative
Monoid
例如MonadPlus
and Alternative
forMaybe
做显而易见的事情:
instance MonadPlus Maybe where
mzero = Nothing
mplus (Just a) _ = Just a
mplus _ mb = mb
但是该Monoid
实例将一个半群提升到一个Monoid
. 可悲的是,因为当时在 Haskell 98 中不存在一个Semigroup
类,它通过要求 a 来做到这一点Monoid
,但不使用它的单位。ಠ_ಠ</p>
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
和Alternative
实例应该相关,但Monoid
可能(有时是)完全不同的东西。