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
статус суперкласу Monad
GHC (якщо ні ще в мовному стандарті.)
Фактично, 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
і роблять очевидне:Alternative
Maybe
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
здається, абсолютно однакові (обмеження за модулем суперкласу).