Quali sono le relazioni tra Alternative, MonadPlus (LeftCatch) e MonadPlus (LeftDistributive)?


12

Seguito Qual è un esempio di Monade che è un'alternativa ma non un MonadPlus? :

Supponiamo che sia una monade. Quali sono i rapporti betweem m essere un alternativa , un MonadPlusCatch e MonadPlusDistr ? mmPer ognuna delle sei coppie possibili, vorrei avere una prova che l'una implica un'altra o un controesempio che non lo è.

(Sto usando

  • MonadPlusCatch per distinguere un MonadPlus che soddisfa la regola Left-Catch :

    mplus (return a) b = return a
    
  • MonadPlusDistr per distinguere un MonadPlus che soddisfa la regola di distribuzione sinistra :

    mplus a b >>= k = mplus (a >>= k) (b >>= k)
    

vedi MonadPlus su HaskellWiki .)


La mia attuale conoscenza + intuizione è che:

  1. MonadPlusDist Alternativa - probabilmente vera - sembra semplice, credo di avere uno schizzo di una prova, la controllerò e, se è corretta, la pubblicherò AndrewC ha risposto a questa parte.
  2. Maybe
  3. MaybeT (Either e)MaybeT m'

    ((pure x) <|> g) <*> a =    -- LeftCatch
        (pure x) <*> a
    -- which in general cannot be equal to
    ((pure x) <*> a) <|> (g <*> a)
    

    ricontrollerò e invierò. (È interessante notare che Maybeè solo provabile, perché possiamo analizzare se aè Just somethingo Nothing- vedi la risposta di AndrewC sopra menzionata.)

  4. [][]
  5. []
  6. Maybe

Risposte:


8

(perché, come sottolineato da Petr Pudlák, []è un controesempio: non soddisfa MonadPlusCatch ma soddisfa MonadPlusDist , quindi Applicativo )

Supposto: leggi MonadPlusDist

-- (mplus,mzero) is a monoid
mzero >>= k = mzero`                             -- left identity >>=
(a `mplus` b) >>= k  =  (a >>=k) `mplus` (b>>=k) -- left dist mplus

Per provare: leggi alternative

-- ((<|>),empty) is a monoid
(f <|> g) <*> a = (f <*> a) <|> (g <*> a) -- right dist <*>
empty <*> a = empty                       -- left identity <*>
f <$> (a <|> b) = (f <$> a) <|> (f <$> b) -- left dist <$>
f <$> empty = empty                       -- empty fmap

<*>lemma di espansione
Supponiamo di usare la derivazione standard di un applicativo da una monade, vale a dire (<*>) = ape pure = return. Poi

mf <*> mx = mf >>= \f -> mx >>= \x -> return (f x)

perché

mf <*> mx = ap mf mx                                  -- premise
          = liftM2 id mf mx                           -- def(ap)
          = do { f <- mf; x <- mx; return (id f x) }  -- def(liftM2)
          = mf >>= \f -> mx >>= \x -> return (id f x) -- desugaring
          = mf >>= \f -> mx >>= \x -> return (f x)    -- def(id)

<$>lemma di espansione
Supponiamo di usare la derivazione standard di un funzione da una monade, vale a dire (<$>) = liftM. Poi

f <$> mx = mx >>= return . f

perché

f <$> mx = liftM f mx                    -- premise
         = do { x <- mx; return (f x) }  -- def(liftM)
         = mx >>= \x -> return (f x)     -- desugaring
         = mx >>= \x -> (return.f) x     -- def((.))
         = mx >>= return.f               -- eta-reduction 

Prova

Supponiamo che ( <+>, m0) soddisfi le leggi di MonadPlus. In sostanza, allora è un monoide.

Right Dist <*>

Lo dimostrerò

(mf <+> mg) <*> ma = (mf <*> ma) <+> (mg <*> ma) -- right dist <*>

perché è più facile sulla notazione.

(mf <+> mg) <*> ma = (mf <+> mg) >>= \forg -> mx >>= \x -> return (forg x) -- <*> expansion
                   =     (mf >>= \f_g -> mx >>= \x -> return (f_g x))
                     <+> (mg >>= \f_g -> mx >>= \x -> return (f_g x))      -- left dist mplus
                   = (mf <*> mx) <+> (mg <*> mx)                           -- <*> expansion

Identità sinistra <*>

mzero <*> mx = mzero >>= \f -> mx >>= \x -> return (f x) -- <*> expansion
             = mzero                                     -- left identity >>=

come richiesto.

Dist. Sinistra <$>

f <$> (a <|> b) = (f <$> a) <|> (f <$> b) -- left dist <$>

f <$> (a <+> b) = (a <+> b) >>= return . f              -- <$> expansion
                = (a >>= return.f) <+> (b >>= return.f) -- left dist mplus
                = (f <$> a) <+> (f <$> b)               -- <$> expansion

empty fmap

f <$> mzero = mzero >>= return.f   -- <$> expansion
            = mzero                -- left identity >>=

come richiesto


1
Grande. Ho persino il sospetto che le leggi di sinistra siano implicate dalle leggi di destra per qualsiasi Applicativo , ma finora non ho prove. L'intuizione è che f <$>non svolge alcuna azione idiomatica, è pura, quindi potrebbe essere possibile in qualche modo "cambiare lato".
Petr Pudlák,

@ PetrPudlák Aggiornato - prova finita e aggiunto il tuo corollory [].
AndrewC

@ PetrPudlák Pensi che dovremmo aggiungere una prova che []soddisfi MonadPlusCatch? Al momento è solo un'affermazione su HaskellWiki. >>= kviene definito esplicitamente utilizzandofoldr ((++).k)
AndrewC

Suppongo che intendi MonadPlusDist , vero? Penso che potremmo, questo completerebbe la prova del corollario.
Petr Pudlák,

@ PetrPudlák Oh sì, mi dispiace. Andrà bene.
AndrewC,

6

Infatti è MaybeT Either:

{-# LANGUAGE FlexibleInstances #-}
import Control.Applicative
import Control.Monad
import Control.Monad.Trans.Maybe

instance (Show a, Show b) => Show (MaybeT (Either b) a) where
    showsPrec _ (MaybeT x) = shows x

main = print $
    let
        x = id :: Int -> Int
        g = MaybeT (Left "something")
        a = MaybeT (Right Nothing)
    -- print the left/right side of the left distribution law of Applicative:
    in ( ((return x) `mplus` g) `ap` a
       , ((return x) `ap` a) `mplus` (g `ap` a)
       )

L'output è

(Right Nothing, Left "something")

il che significa che MaybeT Eithernon riesce la legge di distribuzione sinistra di Applicative.


Il motivo è questo

(return x `mplus` g) `ap` a

ignora g(a causa di LeftCatch ) e valuta solo per

return x `ap` a

ma questo è diverso da ciò che l'altra parte valuta per:

g `ap` a
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.