MonadPlus
e Monoid
servono a diversi scopi.
A Monoid
è parametrizzato su un tipo di tipo *
.
class Monoid m where
mempty :: m
mappend :: m -> m -> m
e quindi può essere istanziata per quasi qualsiasi tipo per i quali esiste un operatore ovvio che è associativa e che ha un'unità.
Tuttavia, MonadPlus
non solo specifica che si dispone di una struttura monoidale, ma anche che tale struttura è legata al modo in cui le opere, Monad
e che tale struttura non si preoccupano il valore contenuto nella monade, questo è (in parte) indicato dal fatto che MonadPlus
accetta un argomento di tipo * -> *
.
class Monad m => MonadPlus m where
mzero :: m a
mplus :: m a -> m a -> m a
Oltre alle leggi monoid, abbiamo due potenziali serie di leggi che possiamo applicare a MonadPlus
. Purtroppo, la comunità non è d'accordo su cosa dovrebbero essere.
Almeno sappiamo
mzero >>= k = mzero
ma ci sono altre due estensioni in competizione, la legge di sinistra (sic) la distribuzione
mplus a b >>= k = mplus (a >>= k) (b >>= k)
e la legge fermo sinistra
mplus (return a) b = return a
Pertanto, qualsiasi istanza di MonadPlus
dovrebbe soddisfare una o entrambe queste leggi aggiuntive.
Che dire di Alternative
?
Applicative
è stato definito dopo Monad
, e logicamente appartiene come una superclasse di Monad
, ma in gran parte a causa delle diverse pressioni sui progettisti indietro nel Haskell 98, anche Functor
non era una superclasse di Monad
fino al 2015. Ora abbiamo finalmente hanno Applicative
come una superclasse di Monad
a GHC (se non ancora in un linguaggio standard.)
in effetti, è quello di Alternative
Applicative
cosa MonadPlus
è quello di Monad
.
Per questi otterremmo
empty <*> m = empty
analogamente a quanto abbiamo con MonadPlus
ed esistono distributive e di cattura simili proprietà, almeno uno dei quali si dovrebbe soddisfare.
Sfortunatamente, anche la legge empty <*> m = empty
è un'affermazione troppo forte. Ad esempio, non è valido per Backwards!
Quando guardiamo a MonadPlus, il vuoto >> = f = la legge vuota è quasi forzata su di noi. La costruzione vuota non può avere alcun 'a's in esso per chiamare comunque la funzione f
.
Tuttavia, dal momento che non è Applicative
una superclasse di Monad
e Alternative
non è una superclasse di MonadPlus
, finiamo per definire entrambi i casi separatamente.
Inoltre, anche se Applicative
era una superclasse di Monad
, che ci si finisce per dover classe MonadPlus
in ogni modo, perché anche se abbiamo obbediamo
empty <*> m = empty
che non è abbastanza strettamente per dimostrare che
empty >>= f = empty
Quindi affermare che qualcosa è un MonadPlus
è più forte di rivendicare che è Alternative
.
Ora, per convenzione, il MonadPlus
e Alternative
per un determinato tipo dovrebbe concordare, ma la Monoid
può essere completamente diversa.
Per esempio il MonadPlus
e Alternative
per Maybe
fare la cosa più ovvia:
instance MonadPlus Maybe where
mzero = Nothing
mplus (Just a) _ = Just a
mplus _ mb = mb
ma l'istanza Monoid
solleva un semigruppo in un Monoid
. Purtroppo perché non esisteva una classe Semigroup
al momento in Haskell 98, lo fa richiedendo un Monoid
, ma non utilizzando la sua unità.ಠ_ಠ
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
è un'indicazione forte di Alternative
, che a sua volta è un'indicazione forte di Monoid
, e mentre i MonadPlus
e Alternative
istanze di un tipo devono essere riferiti al Monoid
può essere (e qualche volta è) qualcosa di completamente diverso.
Questa è una buona domanda. In particolare, 'Applicativo' e' MonadPlus' sembrano essere * esattamente * gli stessi (vincoli di superclasse modulo). – Peter
Ci sono anche 'ArrowZero' e' ArrowPlus' per le frecce. La mia scommessa: rendere più pulite le firme dei tipi (il che rende i diversi vincoli della superclasse * la * vera differenza). –
@CatPlusPlus: beh, 'ArrowZero' e' ArrowPlus' hanno tipo '* -> * -> *', il che significa che è possibile passarli per il tipo di freccia una volta per una funzione che deve essere utilizzata per una moltitudine di tipi , per usare un 'Monoid' dovresti richiedere un'istanza di' Monoid' per ogni particolare istanza, e non avresti alcuna garanzia che siano stati gestiti in un modo simile, le istanze potrebbero non essere correlate! –