his answer问题“Distinction between typeclasses MonadPlus , Alternative , and Monoid ?”中,爱德华·克梅特(Edward Kmett)说



显然,任何不是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”问题(搜索“正确的分配”一词)的中间位置。我认为应该遵守的四个定律是:

  • (<*>的)右分布: (f <|> g) <*> a = (f <*> a) <|> (g <*> a)
  • 右吸收(对于<*>): empty <*> a = empty
  • (fmap的)左分布: f <$> (a <|> b) = (f <$> a) <|> (f <$> b)
  • 左吸收(对于fmap): f <$> empty = empty

  • 我也很乐意接受一套更有用的Alternative法律。

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

    最佳答案

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



    因此,根据您的偏爱选择,Maybe不是MonadPlus(尽管有一个实例,但它不满足左分布)。让我们证明它满足替代要求。
    Maybe是替代方法

  • (<*>的)右分布: (f <|> g) <*> a = (f <*> a) <|> (g <*> a)

  • 情况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 <*>
    
  • 右吸收(对于<*>): empty <*> a = empty

  • 这很容易,因为
    Nothing <*> a = Nothing    -- left failure <*>
    
  • (fmap的)左分布: f <$> (a <|> b) = (f <$> a) <|> (f <$> b)

  • 情况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 <$>
    
  • 左吸收(对于fmap): f <$> empty = empty

  • 另一个简单的方法:
    f <$> Nothing = Nothing   -- failure <$>
    
    Maybe不是MonadPlus

    让我们证明Maybe不是MonadPlus的断言:我们需要证明mplus a b >>= k = mplus (a >>= k) (b >>= k)并不总是成立。诀窍是,与以往一样,使用一些绑定(bind)来潜入非常不同的值:
    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
    

    在这里,我使用bind (>>=)从胜利的口中抢走失败(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!"

    您可以像我一样使用>>=打破mplusMaybe的左偏。

    我的证明的有效性:

    以防万一您觉得我做得不够单调乏味,我将证明我使用的身份:

    首先
    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,则结果为Just (f x)

    08-03 13:51