MonadPlusи Monoidслужат разным целям.
MonoidПараметр A параметризуется по типу вида *.
class Monoid m where
mempty :: m
mappend :: m -> m -> m
и поэтому его можно создать практически для любого типа, для которого существует очевидный ассоциативный оператор, имеющий единицу измерения.
Однако MonadPlusне только указывает, что у вас есть моноидальная структура, но также и то, что эта структура связана с тем, как она Monadработает, и что эта структура не заботится о значении, содержащемся в монаде, это (частично) указывается фактом это MonadPlusтребует своего рода аргумента * -> *.
class Monad m => MonadPlus m where
mzero :: m a
mplus :: m a -> m a -> m a
В дополнение к моноидным законам у нас есть два потенциальных набора законов, к которым мы можем применить MonadPlus. К сожалению, сообщество не согласны с тем, какими они должны быть.
По крайней мере, мы знаем
mzero >>= k = mzero
но есть два других конкурирующих расширения, левый (sic) закон распределения
mplus a b >>= k = mplus (a >>= k) (b >>= k)
и закон левого улова
mplus (return a) b = return a
Таким образом, любой экземпляр MonadPlusдолжен удовлетворять одному или обоим этим дополнительным законам.
Так что насчет Alternative?
Applicativeбыл определен позже Monadи логически принадлежит к суперклассу Monad, но в значительной степени из-за различного давления на разработчиков еще в Haskell 98, даже Functorне был суперклассом Monadдо 2015 года. Теперь у нас, наконец, есть Applicativeсуперкласс MonadGHC (если не пока что в языковом стандарте.)
Фактически, Alternativeэто Applicativeто, что MonadPlusнужно Monad.
Для этого мы получим
empty <*> m = empty
аналогично тому, что у нас есть, MonadPlusи существуют аналогичные свойства распределения и захвата, по крайней мере, одно из которых вы должны удовлетворить.
К сожалению, даже empty <*> m = emptyзакон слишком силен. Например, он не работает в обратном направлении !
Когда мы смотрим на MonadPlus, нам почти навязывают закон пустой >> = f = пустой. Пустая конструкция не может содержать никаких букв для вызова функции f.
Однако, так как Applicativeэто не суперкласс Monadи Alternativeэто не суперкласс MonadPlus, мы заводиться определения обоих экземпляров отдельно.
Более того, даже если бы это Applicativeбыл суперкласс Monad, вам все MonadPlusравно понадобился бы этот класс, потому что даже если бы мы подчинялись
empty <*> m = empty
этого недостаточно, чтобы доказать, что
empty >>= f = empty
Так что утверждать, что что-то есть, MonadPlusсильнее, чем утверждать, что это так Alternative.
Итак, по соглашению, MonadPlusи Alternativeдля данного типа должны согласовываться, но Monoidмогут быть совершенно разными.
Например, MonadPlusи Alternativeдля Maybeделают очевидную вещь:
instance MonadPlus Maybe where
mzero = Nothing
mplus (Just a) _ = Just a
mplus _ mb = mb
но Monoidэкземпляр поднимает полугруппу в Monoid. К сожалению, поскольку Semigroupв то время в Haskell 98 не существовало класса, он делает это, запрашивая Monoid, но не используя его модуль. ಠ_ಠ
instance Monoid a => Monoid (Maybe a) where
mempty = Nothing
mappend (Just a) (Just b) = Just (mappend a b)
mappend Nothing x = x
mappend x Nothing = x
mappend Nothing Nothing = Nothing
TL; DR MonadPlus является более сильным , чем требование Alternative, которое в свою очередь является более сильным , чем требование Monoid, и в то время , MonadPlusи Alternativeэкземпляры для типа должны быть связаны, то Monoidможет быть (а иногда) нечто совершенно иное.
ApplicativeиMonadPlusкажутся точно такими же (по модулю ограничений суперкласса).