Why MonadPlus and not Monad + Monoid?

前端 未结 3 1070
余生分开走
余生分开走 2020-12-13 23:58

I\'m trying to understand the motivation behind the MonadPlus. Why is it necessary if there are already the typeclasses Monad and Monoid

3条回答
  •  半阙折子戏
    2020-12-14 00:25

    With the QuantifiedConstraints language extension you can express that the Monoid (m a) instance has to be uniform across all choices of 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
    

    Alternatively, we can implement the "real" MonadPlus class generically for all such monoid-monads:

    {-# 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)
    

    Note that depending on your choise of m, this may or may not give you the MonadPlus you expect; for example, MonoidMonad [] is really the same as []; but for Maybe, the Monoid instance lifts some underlying semigroup by artifically giving it an identity element, whereas the MonadPlus instance is left-biased choice; and so we have to use MonoidMonad First instead of MonoidMonad Maybe to get the right instance.

提交回复
热议问题