我正在努力理解MonadPlus背后的动机。如果已经有了类型类Monad和Monoid,为什么有必要?
当然,Monoid的实例是具体的类型,而Monad的实例需要一个类型的参数。(有关有用的解释,请参见Monoid vs MonadPlus。)但是你不能重写任何类型的约束
(MonadPlus m) => ...作为Monad和Monoid的结合
(Monad m, Monoid (m a)) => ...例如,将guard函数从Control.Monad中取出来。它的实施是:
guard :: (MonadPlus m) => Bool -> m ()
guard True = return ()
guard False = mzero我只使用Monad和Monoid实现了它。
guard' :: (Monad m, Monoid (m ())) => Bool -> m ()
guard' True = return ()
guard' False = mempty谁能澄清一下MonadPlus和Monad + Monoid的真正区别吗?
发布于 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更灵活,这种灵活性在以下四种情况下都是有用的:
a。
MonadPlus m => ...而不是Monoid (m SecretType) => ...a。
MonadPlus m => ...而不是(Monoid (m Type1), Monoid (m Type2), ...) => ...a。
MonadPlus m => ...而不是不可能。a。MonadPlus m => ...而不是不可能。发布于 2014-04-11 23:12:44
您的guard'与Monoid m a类型不匹配。
如果您的意思是Monoid (m a),那么您需要定义m ()的mempty是什么。一旦您这样做了,就定义了一个MonadPlus。
换句话说,MonadPlus定义了两个选项:满足两条规则的mzero和mplus:mzero相对于mplus是中性的,mplus是关联的。这满足了Monoid的定义,因此mzero是mempty,mplus是mappend。
不同之处在于,MonadPlus m对于任何a都是一个单样体m a,但是Monoid m只为m定义了一个单样体。您的guard'可以工作,因为您只需要m就可以成为()的Monoid。但是MonadPlus更强大,它声称m a是任何a的一个幺半群。
发布于 2019-07-15 14:19:08
使用 language extension,您可以表示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 = mappendAlternatively,我们可以为所有这样的单核类一般地实现“实”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)请注意,根据您对m的选择,这可能给您提供您所期望的MonadPlus;例如,MonoidMonad []实际上与[]相同;但是对于Maybe,Monoid实例通过人为地给它一个标识元素来提升一些底层半群,而MonadPlus实例是左偏的选择;因此我们必须使用MonoidMonad First而不是MonoidMonad Maybe来获得正确的实例。
https://stackoverflow.com/questions/23023961
复制相似问题