为什么MonadPlus而不是Monad + Monoid?

mxx*_*xxk 35 monads haskell monoids

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

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

(MonadPlus m) => ...
Run Code Online (Sandbox Code Playgroud)

作为MonadMonoid?的组合?

(Monad m, Monoid (m a)) => ...
Run Code Online (Sandbox Code Playgroud)

例如,guard从中获取功能Control.Monad.它的实施是:

guard :: (MonadPlus m) => Bool -> m ()
guard True = return ()
guard False = mzero
Run Code Online (Sandbox Code Playgroud)

我只能使用Monad和实现它Monoid:

guard' :: (Monad m, Monoid (m ())) => Bool -> m ()
guard' True = return ()
guard' False = mempty
Run Code Online (Sandbox Code Playgroud)

有人可以澄清MonadPlusMonad+ 之间的真正区别Monoid吗?

Tox*_*ris 34

但是你不能重写任何类型约束

(MonadPlus m) => ...
Run Code Online (Sandbox Code Playgroud)

作为Monad和Monoid的组合?

在你回答的问题的最佳答案中,对于MonadPlus与Monoid的法律已经有了很好的解释.但即使我们忽略了类型规则,也存在差异.

Monoid (m a) => ...意味着m a必须是a调用者选择的一个特定的幺半群,但MonadPlus m意味着m a必须是所有人的幺半群a.因此MonadPlus a更灵活,这种灵活性有助于四种情况:

  1. 如果我们不想告诉来电者a我们打算使用什么.
    MonadPlus m => ...代替Monoid (m SecretType) => ...

  2. 如果我们想要使用多个不同的a.
    MonadPlus m => ...代替(Monoid (m Type1), Monoid (m Type2), ...) => ...

  3. 如果我们想要使用无限多的不同a.
    MonadPlus m => ...而不是不可能.

  4. 如果我们不知道a我们需要什么. MonadPlus m => ...而不是不可能.


Sas*_* NF 6

guard'Monoid m a类型与您的类型不符.

如果你的意思是Monoid (m a),那么你需要定义什么memptym ().一旦你完成了,你就定义了一个MonadPlus.

换句话说,MonadPlus定义两个操作:mzero并且mplus满足两个规则:mzero相对于中性mplus,并且mplus是关联的.这满足的定义Monoid,这样mzeromemptymplusmappend.

不同之处在于它MonadPlus mm a任何一个幺半群a,但Monoid m仅定义了一个幺半群m.你的guard'作品,因为你只需要m成为一个Monoid只为().但MonadPlus它更强大,它声称m a对任何人都是幺半群a.


Cac*_*tus 5

随着QuantifiedConstraints语言扩展,你可以表达的Monoid (m a)对象必须是跨越所有的选择一致a

{-# 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
Run Code Online (Sandbox Code Playgroud)

Alternatively,我们可以MonadPlus为所有这样的幺半群单子通用地实现“真实”类:

{-# 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)
Run Code Online (Sandbox Code Playgroud)

请注意,根据您对 的选择m,这可能会或可能不会给您带来MonadPlus您期望的结果;例如,MonoidMonad []实际上与[]; 但是对于MaybeMonoid实例通过人为地给它一个恒等元素来提升一些潜在的半群,而MonadPlus实例是左偏选择;所以我们必须使用MonoidMonad First而不是MonoidMonad Maybe来获得正确的实例。