首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >为什么MonadPlus而不是Monad + Monoid?

为什么MonadPlus而不是Monad + Monoid?
EN

Stack Overflow用户
提问于 2014-04-11 23:02:42
回答 4查看 2.1K关注 0票数 41

我正在努力理解MonadPlus背后的动机。如果已经有了类型类MonadMonoid,为什么有必要?

当然,Monoid的实例是具体的类型,而Monad的实例需要一个类型的参数。(有关有用的解释,请参见Monoid vs MonadPlus。)但是你不能重写任何类型的约束

代码语言:javascript
复制
(MonadPlus m) => ...

作为MonadMonoid的结合

代码语言:javascript
复制
(Monad m, Monoid (m a)) => ...

例如,将guard函数从Control.Monad中取出来。它的实施是:

代码语言:javascript
复制
guard :: (MonadPlus m) => Bool -> m ()
guard True = return ()
guard False = mzero

我只使用MonadMonoid实现了它。

代码语言:javascript
复制
guard' :: (Monad m, Monoid (m ())) => Bool -> m ()
guard' True = return ()
guard' False = mempty

谁能澄清一下MonadPlusMonad + Monoid的真正区别吗?

EN

回答 4

Stack Overflow用户

回答已采纳

发布于 2014-04-11 23:31:42

但是你不能重写任何类型的约束 (MonadPlus m) => . 作为Monad和Monoid的组合?

不是的。在你链接的问题的最上面的答案中,已经有一个关于MonadPlus和Monoid定律的很好的解释。但是,即使我们忽略了典型法则,也有不同之处。

Monoid (m a) => ...意味着m a必须是调用方选择的一个特定a的幺半群,而MonadPlus m则意味着m a必须是所有a的单半群。因此,MonadPlus a更灵活,这种灵活性在以下四种情况下都是有用的:

  1. 如果我们不想告诉调用者我们打算使用什么aMonadPlus m => ...而不是Monoid (m SecretType) => ...

  1. 如果我们想使用多个不同的aMonadPlus m => ...而不是(Monoid (m Type1), Monoid (m Type2), ...) => ...

  1. 如果我们想使用无穷多个不同的aMonadPlus m => ...而不是不可能。

  1. 如果我们不知道我们需要什么aMonadPlus m => ...而不是不可能。
票数 38
EN

Stack Overflow用户

发布于 2014-04-11 23:12:44

您的guard'Monoid m a类型不匹配。

如果您的意思是Monoid (m a),那么您需要定义m ()mempty是什么。一旦您这样做了,就定义了一个MonadPlus

换句话说,MonadPlus定义了两个选项:满足两条规则的mzeromplusmzero相对于mplus是中性的,mplus是关联的。这满足了Monoid的定义,因此mzeromemptymplusmappend

不同之处在于,MonadPlus m对于任何a都是一个单样体m a,但是Monoid m只为m定义了一个单样体。您的guard'可以工作,因为您只需要m就可以成为()Monoid。但是MonadPlus更强大,它声称m a是任何a的一个幺半群。

票数 6
EN

Stack Overflow用户

发布于 2019-07-15 14:19:08

使用 language extension,您可以表示Monoid (m a)实例必须在a的所有选项之间保持一致。

代码语言:javascript
复制
{-# LANGUAGE QuantifiedConstraints #-}

class (Monad m, forall a. Monoid (m a)) => MonadPlus m

mzero :: (MonadPlus m) => m a
mzero = mempty

mplus :: (MonadPlus m) => m a -> m a -> m a
mplus = mappend

Alternatively,我们可以为所有这样的单核类一般地实现“实”MonadPlus类:

代码语言:javascript
复制
{-# LANGUAGE GeneralizedNewtypeDeriving, DerivingStrategies, QuantifiedConstraints #-}
{-# LANGUAGE UndecidableInstances #-}

import Control.Monad
import Control.Applicative

newtype MonoidMonad m a = MonoidMonad{ runMonoidMonad :: m a }
    deriving (Functor, Applicative, Monad)

instance (Applicative m, forall a. Monoid (m a)) => Alternative (MonoidMonad m) where
    empty = MonoidMonad mempty
    (MonoidMonad x) <|> (MonoidMonad y) = MonoidMonad (x <> y)

instance (Monad m, forall a. Monoid (m a)) => MonadPlus (MonoidMonad m)

请注意,根据您对m的选择,这可能给您提供您所期望的MonadPlus;例如,MonoidMonad []实际上与[]相同;但是对于MaybeMonoid实例通过人为地给它一个标识元素来提升一些底层半群,而MonadPlus实例是左偏的选择;因此我们必须使用MonoidMonad First而不是MonoidMonad Maybe来获得正确的实例。

票数 5
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/23023961

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档