I\'m trying to understand the motivation behind the MonadPlus. Why is it necessary if there are already the typeclasses Monad and Monoid
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.