MonadPlusі Monoidслужать різним цілям.
A Monoidпараметризується над типом виду *.
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 = порожній закон майже нав'язується нам. Порожня конструкція не може містити символів "a", щоб викликати функцію fв будь-якому випадку.
Однак, так як Applicativeце НЕ суперклас Monadі Alternativeце НЕ суперклас MonadPlus, ми заводитися визначення обох примірників окремо.
Більше того, навіть якби це Applicativeбув суперклас Monad, ти все одно потребував би MonadPlusклас, бо навіть якби ми слухалися
empty <*> m = empty
цього недостатньо строго, щоб довести це
empty >>= f = empty
Тож стверджувати, що щось MonadPlusє сильнішим, ніж стверджувати, що воно є Alternative.
Тепер, за домовленістю, MonadPlusі Alternativeдля даного типу слід узгодити, але це Monoidможе бути зовсім іншим.
Наприклад, for MonadPlusі роблять очевидне:AlternativeMaybe
instance MonadPlus Maybe where
mzero = Nothing
mplus (Just a) _ = Just a
mplus _ mb = mb
але Monoidекземпляр піднімає напівгрупу в Monoid. На жаль, оскільки Semigroupна той час у Haskell 98 не існувало класу, він робить це, вимагаючи a 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здається, абсолютно однакові (обмеження за модулем суперкласу).