90

标准库 Haskell 类型类MonadPlusAlternativeMonoid每个都提供了两个具有基本相同语义的方法:

  • 空值:mzeroemptymempty
  • a -> a -> a将类型类中的值连接在一起的运算符: mplus<|>mappend

这三个都指定了实例应遵守的这些法律:

mempty `mappend` x = x
x `mappend` mempty = x

因此,似乎这三个类型类都提供了相同的方法。

Alternative也提供someand many,但它们的默认定义通常就足够了,因此就这个问题而言,它们并不太重要。)

所以,我的疑问是:为什么有这三个极其相似的类?除了它们不同的超类约束之外,它们之间是否有任何真正的区别?

4

1 回答 1

123

MonadPlusMonoid服务于不同的目的。

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但在语言标准中。)

实际上,AlternativeApplicative什么MonadPlus是什么Monad

对于这些我们会得到

empty <*> m = empty

类似于我们所拥有的,MonadPlus并且存在类似的分配和捕获属性,至少您应该满足其中一个。

不幸的是,即使是empty <*> m = empty法律的要求也太强了。例如,它不适用于Backwards

当我们查看 MonadPlus 时,empty >>= f = empty 定律几乎是强加给我们的。无论如何,空结构中不能有任何'a'来调用函数f

但是,由于Applicative不是的超类,也不类,我们最终分别定义了这两个实例。MonadAlternativeMonadPlus

此外,即使Applicative是 的超类Monad,你最终还是需要这个MonadPlus类,因为即使我们确实服从

empty <*> m = empty

这还不足以证明

empty >>= f = empty

因此,声称某物是 aMonadPlus比声称它是 强Alternative

现在,按照惯例,给定类型的 and 应该是一致的,但MonadPlus可能完全不同AlternativeMonoid

例如MonadPlusand AlternativeforMaybe做显而易见的事情:

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,虽然类型的MonadPlusAlternative实例应该相关,但Monoid可能(有时是)完全不同的东西。

于 2012-04-16T02:36:32.283 回答