【问题标题】:Distinction between typeclasses MonadPlus, Alternative, and Monoid?类型类 MonadPlus、Alternative 和 Monoid 之间的区别?
【发布时间】:2012-04-16 01:53:55
【问题描述】:

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

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

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

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

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

Alternative也提供了somemany,但是它们的默认定义通常就足够了,所以对于这个问题来说它们并不是太重要。)

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

【问题讨论】:

  • 这是个好问题。特别是,ApplicativeMonadPlus 似乎完全相同相同(模超类约束)。
  • 还有ArrowZeroArrowPlus 用于箭头。我的赌注:使类型签名更清晰(这使得不同的超类约束真正不同)。
  • @CatPlusPlus: 好吧,ArrowZeroArrowPlus 有类似的* -> * -> *,这意味着您可以将它们传递给箭头类型一次,用于需要使用它们的函数类型,要使用Monoid,您必须为每个特定的实例化一个Monoid 的实例,并且您不能保证它们以类似的方式处理,这些实例可能是不相关的!

标签: haskell applicative monoids alternative-functor monadplus


【解决方案1】:

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 也不是@ 的超类987654343@ 直到 2015 年。现在我们终于在 GHC 中将 Applicative 作为 Monad 的超类(如果还没有在语言标准中。)

实际上,AlternativeApplicativeMonadPlusMonad

我们会得到这些

empty <*> m = empty

MonadPlus 类似,存在类似的分配和捕获属性,您至少应该满足其中一个。

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

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

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

此外,即使 ApplicativeMonad 的超类,你最终还是需要 MonadPlus 类,因为即使我们确实遵守了

empty <*> m = empty

这还不足以证明这一点

empty >>= f = empty

因此,声称某事物是MonadPlus 比声称它是Alternative 要强。

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

例如,MonadPlusAlternative for 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 更强的声明,而 Alternative 又是比 Monoid 更强的声明,而 MonadPlusAlternative 实例类型应该是相关的,Monoid 可能(有时是)完全不同的东西。

【讨论】:

  • 很好的答案,但是最后一个定义似乎是错误的,它不满足mempty `mappend` x ≡ x
  • 很好的答案。有谁知道具有 不同 MonadPlusAlternative 实现的(常用)类型?
  • @EdwardKmett:这个答案似乎暗示可能有一个Monad,它是一个Alternative,但不是MonadPlus。我asked a question 想找到一个具体的例子;如果你知道,我很想看看。
  • @benw 左分布可以说是更明智的法则,但在某些情况下并不成立。 left catch 是其他情况倾向于支持但大多数其他情况不支持的替代法则。因此,我们确实有 2 组基本不相关的法律正在由不同的实例实施,所以 MonadPlus 实际上是两个伪装成一个的类,因为大多数人并不关心。
  • @EdwardKmett:这似乎是一个满足左捕获和左分布规律的 monad plus 必须忽略 mplus 的右参数。使用左捕获我们有:mplus (return a) b &gt;&gt;= k = return a &gt;&gt;= k = k a 使用左分布:mplus (return a) b &gt;&gt;= k = mplus (return a &gt;&gt;= k) (b &gt;&gt;= k) = mplus (k a) (b &gt;&gt;= k) 所以:mplus (k a) (b &gt;&gt;= k) = k a
猜你喜欢
  • 2012-12-09
  • 2013-10-05
  • 2016-09-28
  • 2013-11-17
  • 2013-06-08
  • 2021-01-12
  • 1970-01-01
  • 2013-05-19
  • 2015-11-07
相关资源
最近更新 更多