Monad是一个替代但不是MonadPlus的例子是什么?

时间:2012-10-29 13:22:53

标签: math haskell monads applicative

在问题his answer“Distinction between typeclasses MonadPlus, Alternative, and Monoid?”中,Edward Kmett说

  

此外,即使ApplicativeMonad的超类,您仍然需要MonadPlus课程,因为服从

empty <*> m = empty
     

并不足以证明

empty >>= f = empty
     

声称某事物是MonadPlus比宣称Alternative更强。

很明显,任何 monad的应用函子都会自动成为Alternative的一个例子而不是MonadPlus,但Edward Kmett的回答暗示存在一个 monad ,它是Alternative但不是MonadPlus:其empty<|>符合Alternative定律, 1 但不是MonadPlus定律。 2 我不能自己想出一个例子;有人知道吗?


1 我无法找到一组Alternative定律的规范参考,但我列出了我认为它们大致在my answer的中途。问题“Confused by the meaning of the Alternative type class and its relationship to other type classes”(搜索“正确的分配”一词)。我认为应该遵守的四项法律是:

  1. 正确的分配(<*>): (f <|> g) <*> a = (f <*> a) <|> (g <*> a)
  2. 正确吸收(适用于<*>): empty <*> a = empty
  3. 左派分布(fmap): f <$> (a <|> b) = (f <$> a) <|> (f <$> b)
  4. 左吸收(fmap): f <$> empty = empty
  5. 我也很乐意接受一套更有用的Alternative法律。

    2 我知道there’s some ambiguity about what the MonadPlus laws are;我对使用左派或左派的答案感到满意,尽管我不喜欢前者。

1 个答案:

答案 0 :(得分:24)

答案的线索在HaskellWiki about MonadPlus you linked to

  

哪个规则?马丁&amp; Gibbons选择Monoid,Left Zero和Left Distribution。这使[]成为MonadPlus,但不是MaybeIO

所以根据你喜欢的选择,Maybe不是MonadPlus(尽管有一个实例,它不满足左派分布)。让我们证明它满足替代方案。

Maybe是另类

  1. 正确的分配(<*>): (f <|> g) <*> a = (f <*> a) <|> (g <*> a)
  2. 案例1:f=Nothing

    (Nothing <|> g) <*> a =                    (g) <*> a  -- left identity <|>
                          = Nothing         <|> (g <*> a) -- left identity <|>
                          = (Nothing <*> a) <|> (g <*> a) -- left failure <*>
    

    案例2:a=Nothing

    (f <|> g) <*> Nothing = Nothing                             -- right failure <*>
                          = Nothing <|> Nothing                 -- left identity <|>
                          = (f <*> Nothing) <|> (g <*> Nothing) -- right failure <*>
    

    案例3:f=Just h, a = Just x

    (Just h <|> g) <*> Just x = Just h <*> Just x                      -- left bias <|>
                              = Just (h x)                             -- success <*>
                              = Just (h x) <|> (g <*> Just x)          -- left bias <|>
                              = (Just h <*> Just x) <|> (g <*> Just x) -- success <*>
    
    1. 正确吸收(适用于<*>): empty <*> a = empty
    2. 这很简单,因为

      Nothing <*> a = Nothing    -- left failure <*>
      
      1. 左派分布(fmap): f <$> (a <|> b) = (f <$> a) <|> (f <$> b)
      2. 案例1:a = Nothing

        f <$> (Nothing <|> b) = f <$> b                        -- left identity <|>
                         = Nothing <|> (f <$> b)          -- left identity <|>
                         = (f <$> Nothing) <|> (f <$> b)  -- failure <$>
        

        案例2:a = Just x

        f <$> (Just x <|> b) = f <$> Just x                 -- left bias <|>
                             = Just (f x)                   -- success <$>
                             = Just (f x) <|> (f <$> b)     -- left bias <|>
                             = (f <$> Just x) <|> (f <$> b) -- success <$>
        
        1. 左吸收(fmap): f <$> empty = empty
        2. 另一个简单的方法:

          f <$> Nothing = Nothing   -- failure <$>
          

          Maybe不是MonadPlus

          让我们证明Maybe不是MonadPlus的断言:我们需要证明mplus a b >>= k = mplus (a >>= k) (b >>= k)并不总是成立。与以往一样,诀窍是使用一些绑定来隐藏不同的值:

          a = Just False
          b = Just True
          
          k True = Just "Made it!"
          k False = Nothing
          

          现在

          mplus (Just False) (Just True) >>= k = Just False >>= k
                                               = k False
                                               = Nothing
          

          这里我使用了绑定(>>=)从胜利的下颚抢夺失败(Nothing),因为Just False看起来很成功。

          mplus (Just False >>= k) (Just True >>= k) = mplus (k False) (k True)
                                                     = mplus Nothing (Just "Made it!")
                                                     = Just "Made it!"
          

          此处失败(k False)是早期计算的,因此被忽略了,我们"Made it!"

          所以,mplus a b >>= k = Nothingmplus (a >>= k) (b >>= k) = Just "Made it!"

          您可以使用>>=来查看此内容,以打破mplus Maybe的左侧偏见。

          我的证明的有效性:

          万一你觉得我做得不够乏味,我会证明我使用过的身份:

          首先

          Nothing <|> c = c      -- left identity <|>
          Just d <|> c = Just d  -- left bias <|>
          

          来自实例声明

          instance Alternative Maybe where
              empty = Nothing
              Nothing <|> r = r
              l       <|> _ = l
          

          其次

          f <$> Nothing = Nothing    -- failure <$>
          f <$> Just x = Just (f x)  -- success <$>
          

          来自(<$>) = fmap

          instance  Functor Maybe  where
              fmap _ Nothing       = Nothing
              fmap f (Just a)      = Just (f a)
          

          第三,其他三个需要做更多的工作:

          Nothing <*> c = Nothing        -- left failure <*>
          c <*> Nothing = Nothing        -- right failure <*>
          Just f <*> Just x = Just (f x) -- success <*>
          

          来自定义

          instance Applicative Maybe where
              pure = return
              (<*>) = ap
          
          ap :: (Monad m) => m (a -> b) -> m a -> m b
          ap =  liftM2 id
          
          liftM2  :: (Monad m) => (a1 -> a2 -> r) -> m a1 -> m a2 -> m r
          liftM2 f m1 m2          = do { x1 <- m1; x2 <- m2; return (f x1 x2) }
          
          instance  Monad Maybe  where
              (Just x) >>= k      = k x
              Nothing  >>= _      = Nothing
              return              = Just
          

          所以

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

          因此,如果mfmx为Nothing,则结果也为Nothing,而如果mf = Just fmx = Just x,结果为{{1} }