MonadPlus
i Monoid
służą do różnych celów.
Parametr Monoid
jest parametryzowany w odniesieniu do rodzaju *
.
class Monoid m where
mempty :: m
mappend :: m -> m -> m
i tak można utworzyć instancję dla prawie każdego typu, dla którego istnieje oczywisty operator, który jest skojarzony i który ma jednostkę.
Jednak MonadPlus
określa nie tylko, które mają strukturę monoidal, ale również, że struktura jest związana z jak Monad
prace, i że struktura nie dba o wartości zawartej w monady, to jest (częściowo) wskazane przez fakt, że MonadPlus
przyjmuje argument rodzaju * -> *
.
class Monad m => MonadPlus m where
mzero :: m a
mplus :: m a -> m a -> m a
Poza prawami monoid mamy dwa potencjalne zestawy przepisów możemy zastosować do MonadPlus
. Niestety, społeczność nie zgadza się co do tego, czym powinny być.
Przynajmniej wiemy
mzero >>= k = mzero
ale istnieją dwa inne konkurujące rozszerzenia, prawa (sic!) Dystrybucja lewej
mplus a b >>= k = mplus (a >>= k) (b >>= k)
i lewo prawo połowu
mplus (return a) b = return a
Tak więc każdy przypadek MonadPlus
powinien spełniać jedno lub oba te dodatkowe prawa.
A co z Alternative
?
Applicative
został zdefiniowany po Monad
i logicznie należy jako nadklasą Monad
, ale w dużej mierze z powodu różnych nacisków na projektantów z powrotem w Haskell 98, nawet Functor
nie było nadklasą Monad
aż 2015. Teraz możemy wreszcie mają Applicative
jako nadklasą Monad
w GHC (jeśli nie są jeszcze w normie językowej.)
Skutecznie Alternative
jest Applicative
co MonadPlus
ma Monad
.
dla tych chcielibyśmy dostać
empty <*> m = empty
analogicznie do tego, co mamy z MonadPlus
i istnieją podobne właściwości rozdzielcze i połowowe, z których przynajmniej jeden powinien spełniać.
Niestety, nawet prawo empty <*> m = empty
jest zbyt silnym roszczeniem. Na przykład nie ma dla Backwards!
Kiedy patrzymy na MonadPlus, puste >> = f = puste prawo jest prawie na nas wymuszone. Pusta konstrukcja nie może zawierać żadnych znaków "a", aby wywołać funkcję f
.
Jednak od Applicative
jest nie nadklasą Monad
i Alternative
jest nie nadklasą MonadPlus
, możemy skończyć zdefiniowania obu instancji oddzielnie.
Ponadto, nawet jeśli Applicative
był nadklasą Monad
, że można skończyć konieczności klasę MonadPlus
anyways, bo nawet jeśli nie słuchać
empty <*> m = empty
że nie jest na tyle ściśle, aby udowodnić, że
empty >>= f = empty
A więc twierdzenie, że coś jest jest silniejsze niż twierdzenie, że jest to Alternative
.
Obecnie przyjmuje się, że MonadPlus
i Alternative
dla danego typu powinny uzgodnić, ale Monoid
może być całkowicie inaczej.
Na przykład MonadPlus
i Alternative
dla Maybe
zrobić oczywistą rzeczą:
instance MonadPlus Maybe where
mzero = Nothing
mplus (Just a) _ = Just a
mplus _ mb = mb
ale instancja Monoid
podnosi półgrupa w Monoid
. Niestety, ponieważ w tym czasie nie było klasy Semigroup
w Haskell 98, robi się to przez żądanie Monoid
, ale nie używając jej jednostki.ಠ_ಠ
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; DRMonadPlus
jest silniejsze żądanie niż Alternative
, które z kolei jest mocniejsze żądanie niż Monoid
i a MonadPlus
i Alternative
przykłady dla typu należy pokrewnej, Monoid
może być (a czasami jest) coś zupełnie innego.
To dobre pytanie. W szczególności, 'Applicative' i' MonadPlus' wydają się być dokładnie takie same (ograniczenia superklasy modulo). – Peter
Istnieje również strzałka "ArrowZero" i "ArrowPlus". Mój zakład: sprawić, by podpisy były czystsze (co sprawia, że różnice w klasie nadrzędnej są * rzeczywistą różnicą). –
@CatPlusPlus: Cóż, 'ArrowZero' i' ArrowPlus' mają rodzaj '* -> * -> *', co oznacza, że możesz przekazać je dla typu strzałki raz dla funkcji, która musi ich użyć dla wielu typów , aby użyć 'Monoid', musiałbyś wymagać instancji' Monoid' dla każdej konkretnej instancji i nie miałbyś żadnej gwarancji, że będą one obsługiwane w podobny sposób, instancje mogą być niezwiązane! –