类型类 MonadPlus、Alternative 和 Monoid 之间的区别



标准库Haskell类型类MonadPlusAlternativeMonoid分别提供了两个语义基本相同的方法:

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

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

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

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

Alternative也提供了somemany,但它们的默认定义通常就足够了,所以它们在这个问题上不太重要。

所以,我的问题是:为什么这三个类非常相似?除了它们不同的超类约束之外,它们之间有什么真正的区别吗?

MonadPlusMonoid有不同的用途。

Monoid通过一种类型*进行参数化。

class Monoid m where
    mempty :: m
    mappend :: m -> m -> m

因此,它几乎可以实例化为任何类型,其中有一个明显的运算符是关联的并且有一个单元。

但是,MonadPlus不仅指定您有一个幺半结构,而且还指定该结构与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对设计师的不同压力,即使Functor直到2015年才成为Monad的超类。现在我们终于有了Applicative作为GHC中Monad的超类(如果还没有语言标准的话)。

实际上,AlternativeApplicative MonadPlus Monad

对于这些,我们会得到

empty <*> m = empty

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

不幸的是,即使是empty <*> m = empty法律也太强硬了。例如,它不适用于向后!

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

然而,由于Applicative不是Monad的超类,而Alternative也不是MonadPlus的超类,我们最终分别定义这两个实例。

此外,即使ApplicativeMonad的超阶级,你最终也需要MonadPlus类,因为即使我们服从

empty <*> m = empty

这还不足以证明这一点

empty >>= f = empty

因此,声称某物是MonadPlus比声称它是Alternative更强大。

现在,按照惯例,给定类型的MonadPlusAlternative应该一致,但Monoid可能完全不同。

例如,MaybeMonadPlusAlternative做了显而易见的事情:

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

最新更新