Каковы отношения между Альтернативой, MonadPlus (LeftCatch) и MonadPlus (LeftDistributive)?

12

В продолжение Каков пример Монады, которая является Альтернативой, но не МонадПлюс? :

Предположим, является монадой. Каковы отношения betweem м будучи Alternative , а MonadPlusCatch и MonadPlusDistr ? mmДля каждой из шести возможных пар я хотел бы иметь либо доказательство того, что одно подразумевает другое, либо контрпример, что это не так.

(Я использую

  • MonadPlusCatch, чтобы отличить MonadPlus, который удовлетворяет правилу Left-Catch :

    mplus (return a) b = return a
    
  • MonadPlusDistr, чтобы отличить MonadPlus, который защищает правило левого распределения :

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

см. MonadPlus на HaskellWiki .)


Мои нынешние знания + интуиция таковы:

  1. MonadPlusDist Альтернатива - скорее всего, правда - это кажется простым, я думаю, что у меня есть набросок доказательства, я его проверю и, если он правильный, я опубликую, AndrewC ответил на эту часть.
  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)
    

    еще раз проверю и выложу. (Интересно, что только Maybeэто доказуемо, потому что мы можем проанализировать, если aесть Just somethingили Nothing- см. Ответ вышеупомянутого AndrewC.)

  4. [][]
  5. []
  6. Maybe
Петр Пудлак
источник

Ответы:

8

(потому что, как указал Петр Пудлак, []это контрпример - он не удовлетворяет MonadPlusCatch, но удовлетворяет MonadPlusDist , следовательно, Applicative )

Принято: MonadPlusDist Законы

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

Доказать: альтернативные законы

-- ((<|>),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

<*>лемма о расширении
Предположим, что мы используем стандартный вывод аппликатива из монады, а именно (<*>) = apи pure = return. потом

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

так как

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)

<$>лемма о расширении
Предположим, что мы используем стандартный вывод функтора из монады, а именно (<$>) = liftM. потом

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

так как

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 

доказательство

Предположим, ( <+>, m0) удовлетворяют законам MonadPlus. Тривиально, тогда это моноид.

Right Dist <*>

Я докажу

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

потому что это проще в обозначениях.

(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

Левая идентичность <*>

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

как требуется.

Левый дист <$>

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 >>=

как требуется

AndrewC
источник
1
Отлично. Я даже подозреваю, что левые законы подразумеваются правыми законами для любого заявителя , но у меня пока нет доказательств. Интуиция заключается в том, что f <$>она не несет никаких идиоматических действий, она чистая, поэтому можно как-то «поменять стороны».
Петр Пудлак
@ PetrPudlák Обновлено - закончил доказательство и добавил свое следствие [].
AndrewC
@ PetrPudlák Как вы думаете, мы должны добавить доказательство, которое []удовлетворяет MonadPlusCatch? На данный момент это просто утверждение на HaskellWiki. >>= kопределяется явно с помощьюfoldr ((++).k)
AndrewC
Я полагаю, вы имеете в виду MonadPlusDist , не так ли? Я думаю, что мы могли бы, это завершило бы доказательство следствия.
Петр Пудлак
@ PetrPudlák О, да, я прошу прощения. Сделаю.
AndrewC
6

На самом деле это 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)
       )

Выход

(Right Nothing, Left "something")

Это означает, что MaybeT Eitherне соответствует закону левого распределения Applicative.


Причина в том, что

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

игнорирует g(из-за LeftCatch ) и оценивает только

return x `ap` a

но это отличается от того, что оценивает другая сторона:

g `ap` a
Петр Пудлак
источник