标准库的Haskell类型类MonadPlus
,Alternative
和Monoid
各自提供两种方法,它们的语义基本相同:
mzero
,empty
或mempty
。 a -> a -> a
:mplus
,<|>
或mappend
。 这三个规则均指定了实例应遵循的以下法律:
mempty `mappend` x = x
x `mappend` mempty = x
因此,似乎三个类型类都提供相同的方法。
(
Alternative
还提供了some
和many
,但是它们的默认定义通常就足够了,因此在这个问题上它们并不是太重要。)因此,我的查询是:为什么这三个类非常相似?除了它们不同的父类(super class)约束之外,它们之间是否还有真正的区别?
最佳答案
MonadPlus
和Monoid
具有不同的用途。
在类型Monoid
上参数化*
。
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
除了monoid法则,我们还有两个可能适用于
MonadPlus
的法则集。令人遗憾的是,社区对于应该成为什么样的人持不同意见。至少我们知道
mzero >>= k = mzero
但是还有另外两个相互竞争的扩展,即左(原文如此)分布定律
mplus a b >>= k = mplus (a >>= k) (b >>= k)
和左捕捉法则
mplus (return a) b = return a
因此,
MonadPlus
的任何实例都应满足这些附加法则中的一个或两个。那么
Alternative
呢? Applicative
是在Monad
之后定义的,并且逻辑上属于Monad
的父类(super class),但很大程度上是由于Haskell 98中对设计人员的压力不同,即使Functor
在2015年之前都不是Monad
的父类(super class)。现在,我们终于有了Applicative
作为父类(super class)GHC中Monad
的数量(如果尚未使用语言标准)。实际上,
Alternative
是Applicative
,MonadPlus
是Monad
。对于这些,我们会得到
empty <*> m = empty
与
MonadPlus
类似,并且存在类似的分布和捕获属性,您至少应满足其中之一。不幸的是,即使
empty <*> m = empty
法也没有足够的主张。例如,它不适用于Backwards!当我们看MonadPlus时,空>> = f =空定律几乎被强加给我们。无论如何,空结构中不能包含任何“a”来调用函数
f
。但是,由于
Applicative
不是Monad
的父类(super class),并且Alternative
并非MonadPlus
的父类(super class),因此我们分别定义了两个实例。而且,即使
Applicative
是Monad
的父类(super class),您仍然需要MonadPlus
类,因为即使我们遵守了empty <*> m = empty
这还不足以证明
empty >>= f = empty
因此,宣称某事是
MonadPlus
比宣称它是Alternative
更强。现在,按照约定,给定类型的
MonadPlus
和Alternative
应该一致,但是Monoid
可能完全不同。例如,
MonadPlus
的Alternative
和Maybe
做明显的事情:instance MonadPlus Maybe where
mzero = Nothing
mplus (Just a) _ = Just a
mplus _ mb = mb
但是
Monoid
实例将一个半组提升为Monoid
。令人遗憾的是,由于Haskell 98当时不存在Semigroup
类,因此它通过重新请求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
更具说服力,并且尽管类型的Alternative
和Monoid
实例应该相关,但是ojit_code可能(有时是)完全不同。