2014-04-11 32 views
33

Sto cercando di capire le motivazioni alla base dello MonadPlus. Perché è necessario se ci sono già i typeclasses Monad e Monoid?Perché MonadPlus e non Monad + Monoid?

Concesso, le istanze di Monoid sono tipi concreti, mentre le istanze di Monad richiedono un singolo parametro di tipo. (Vedere Monoid vs MonadPlus per una spiegazione utile.), Ma non si potrebbe riscrivere qualsiasi tipo di vincolo di

(MonadPlus m) => ... 

come una combinazione di Monad e Monoid?

(Monad m, Monoid (m a)) => ... 

Prendere la funzione guard da Control.Monad, per esempio. La sua attuazione è:

guard :: (MonadPlus m) => Bool -> m() 
guard True = return() 
guard False = mzero 

sono stato in grado di attuarlo utilizzando solo Monad e Monoid:

guard' :: (Monad m, Monoid (m())) => Bool -> m() 
guard' True = return() 
guard' False = mempty 

Qualcuno potrebbe chiarire la vera differenza tra MonadPlus e Monad + Monoid?

risposta

32

Ma non si potrebbe riscrivere qualsiasi tipo di vincolo di

(MonadPlus m) => ... 

come una combinazione di Monade e Monoide?

No. Nella risposta superiore alla domanda che si collega, c'è già una buona spiegazione sulle leggi di MonadPlus rispetto a Monoid. Ma ci sono delle differenze anche se ignoriamo le leggi sul tipo.

Monoid (m a) => ... significa che m a deve essere un monoide per una particolare a scelta dal chiamante, ma MonadPlus m significa che m a deve essere un monoide per tutti a. Così MonadPlus a è più flessibile, e questa flessibilità è utile in quattro situazioni:

  1. Se non vogliamo dire al chiamante quello a intendiamo utilizzare.
    MonadPlus m => ... invece di Monoid (m SecretType) => ...

  2. Se vogliamo utilizzare più diversi a.
    MonadPlus m => ... invece di (Monoid (m Type1), Monoid (m Type2), ...) => ...

  3. Se vogliamo usare infiniti diversi a.
    MonadPlus m => ... anziché non possibile.

  4. Se non sappiamo che cosa è necessario a. MonadPlus m => ... anziché non possibile.

+0

Se non ti dispiace, mi piacerebbe davvero vedere un esempio concreto qui. Puoi fornire alcune istanze utilizzando Monade specifiche in cui MonadPlus è più utile o più pulito di Monoid? – Fresheyeball

+0

@Fresheyeball: No, non posso fornire "alcune istanze che usano specifiche Monade", mi dispiace. Se la monade è conosciuta, non c'è bisogno di astrarre su m, e non c'è bisogno di usare alcuna classe di tipi per specificare l'interfaccia prevista di m, quindi la differenza tra 'MonadPlus' e' Monoid' non importa se il tuo codice funziona solo con una particolare monade. – Toxaris

+0

Lo capisco. Ma è difficile concettualizzare la pratica senza vedere in che modo specifiche monadi potrebbero funzionare con codice generalizzato. – Fresheyeball

6

Il tuo guard' non corrisponde al tuo tipo Monoid m a.

Se si intende Monoid (m a), quindi è necessario definire cosa mempty è per m(). Dopo averlo fatto, hai definito uno MonadPlus.

In altre parole, MonadPlus definisce due opeartions: mzero e mplus soddisfare due regole: mzero è neutrale rispetto a mplus, e mplus è associativa. Questo soddisfa la definizione di Monoid in modo che mzero sia mempty e mplus sia mappend.

La differenza è che MonadPlus m è un monoide m a per qualsiasi a, ma Monoid m definisce un monoide solo per m. Il tuo guard' funziona perché hai solo bisogno di m per essere un Monoid solo per (). Ma il numero MonadPlus è più forte, afferma che m a è un monoid per qualsiasi a.