【问题标题】:Monoid vs MonadPlus [duplicate]Monoid vs MonadPlus [重复]
【发布时间】:2013-06-08 01:21:41
【问题描述】:

我对@9​​87654325@ 和Monoids 都很陌生,最近还了解了MonadPlus。在我看来,MonoidMonadPlus 都提供了一个具有关联二元运算和标识的类型。 (用数学术语我称之为半群。)那么MonoidMonadPlus 之间有什么区别?

【问题讨论】:

标签: haskell monads typeclass monoids monadplus


【解决方案1】:

semigroup 是一个配备关联二元运算的结构。 monoid 是一个带有用于二元运算的单位元的半群。

单子和半群

每个 monad 都必须遵守 the monad laws。对于我们的例子,重要的是结合律。用>>=表示:

(m >>= f) >>= g     ≡   m >>= (\x -> f x >>= g)

现在让我们应用这个定律来推断>> :: m a -> m b -> m b 的关联性:

(m >> n) >> p       ≡ (m >>= \_ -> n) >>= \_ -> p
                    ≡ m >>= (\x -> (\_ -> n) x >>= \_ -> p)
                    ≡ m >>= (\x -> n >>= \_ -> p)
                    ≡ m >>= (\x -> n >> p)
                    ≡ m >> (n >> p)

(我们选择了x,这样它就不会出现在mnp 中)。

如果我们将>> 特化为m a -> m a -> m a 类型(用b 代替a),我们会看到对于任何类型a,操作>>m a 上形成一个半群. 因为任何a 都成立,所以我们得到了一个由a 索引的半群类。但是,它们通常不是幺半群——我们没有>> 的标识元素。

MonadPlus 和幺半群

MonadPlus 增加了两个操作,mplusmzeroMonadPlus laws 明确声明 mplusmzero 必须在 m a 上形成一个幺半群,以获得任意 a。再次,我们得到了由a 索引的类幺半群。

注意MonadPlusMonoid 之间的区别:Monoid 表示某些单一类型满足幺半群规则,而MonadPlus 表示对于所有可能的a 类型m a 满足幺半群规则。这是一个更强大的条件。

所以MonadPlus 实例形成了两种不同的代数结构:一类具有>> 的半群和一类具有mplusmzero 的幺半群。 (这并不少见,例如大于零的自然数集{1,2,...}+ 形成一个半群,与×1 形成一个幺半群。)

【讨论】:

  • 所以MonadPlusmplus 也是半群,对吧?
  • @Code-Guru 完全正确 - 如果我们去掉恒等元素,任何幺半群也是半群。
  • 不是(a->m a)>=> 也是一个幺半群,身份为return
  • @Hjulle 对于固定的a,它是moniod can be viewed as a category with a single object
  • @Fresheyeball 是的,带有 0 和 + 的自然数形成一个幺半群,而带有 + 的正自然数只形成一个半群,但带有 * 和 1 的正自然数形成一个幺半群。 (确切地说,说“+ 是一个幺半群”并不是 100% 准确的——代数结构必须始终作为一个集合及其所有操作给出。)
【解决方案2】:

如果我们有 MonadPlus m 成立,那么你会说 mMonad,但 m a(将 a 应用于类型“函数”m 产生的类型)是幺半群。

如果我们定义(类似于Data.Monoid的定义,但我们稍后会用到)

class                Semigroup a where  (<>) :: a -> a -> a
class Semigroup a => Monoid    a where  zero :: a

那么它有

mzero :: MonadPlus m => m a
mplus :: MonadPlus m => m a -> m a -> m a

具有相当相似的类型和适当的法律

-- left and right identity
mplus a     mzero   ==   a
mplus mzero a       ==   a

-- associativity
(a `mplus` b) `mplus` c   ==   a `mplus` (b `mplus` c)

如果我们使用-XFlexibleInstances,我们甚至可以定义一个Haskell Monoid

{-# LANGUAGE FlexibleInstances #-}
instance MonadPlus m => Semigroup (m a) where  (<>) = mplus
instance MonadPlus m => Monoid    (m a) where  zero = mzero

尽管这些与Data.Monoid 中的实例严重重叠,这可能就是它不是标准实例的原因。


像这样的幺半群的另一个例子是来自Control.ApplicativeAlternative m =&gt; m a

【讨论】:

  • MonadPlus 有一些与Monad 相互作用的规律;例如(a `mplus` b) &gt;&gt;= f = (a &gt;&gt;= f) `mplus` (b &gt;&gt;= f).
  • 重新与Data.Monoid 重叠:这正是我所困惑的。为什么forall a. MonadPlus m =&gt; Monoid (m a) 不会自动出现这种情况?如果我们不担心向后兼容性,并且可以假设-XFlexibleInstances,那么是否有任何进一步的理由不自动保持?
  • @dubiousjim 考虑一下:Just "a" `mappend` Just "b" == Just "ab", Just "a" `mplus` Just "b" == Just "a"
【解决方案3】:

我必须强调非常重要的区别:与 Monoid 不同,与其他答案状态不同,MonadPlus 确实提供具有关联二元运算和标识的类型。 Haskell 报告是唯一可以声称标准状态的文档,它没有指定 MonadPlus 的法律,因此不需要 mplus 是关联的或 mzero 成为它的左或右单位。也许作者们仍在争论这些法律:mplus 有很好的理由不具有关联性。例如,如果 mplus 是关联但不可交换的,那么 MonadPlus 所代表的非确定性搜索计算就不能完成(即存在我们找不到的解)。由于 mplus 是可交换的非常罕见,如果我们坚持关联性,任何完整的非确定性搜索过程都不能用 MonadPlus 表示。已经详细讨论了 SC 上的 MonadPlus 法律这个问题:Must mplus always be associative

【讨论】:

    猜你喜欢
    • 2014-05-26
    • 1970-01-01
    • 2011-02-07
    • 1970-01-01
    • 2012-09-17
    • 2011-03-29
    • 2011-05-18
    • 2018-08-01
    • 2015-11-15
    相关资源
    最近更新 更多