haskell 匹配MaybeT的Monad和Applicative的上下文:我发现了一个反例

zrfyljdw  于 2023-04-21  发布在  其他
关注(0)|答案(2)|浏览(131)

I wonder if Applicative is derived naturally through MonadTransformer's Monad
我花了很长时间才弄清楚MaybeT的Monad和Applicative是否有相同的上下文。正如你在上面的链接中看到的。
“同一语境”的意思是

f <*> a = do
          x <- f
          y <- a
          return (x y)

我为MaybeT找到了一个反例。

f = MaybeT [Nothing] :: MaybeT [] (Int -> Int)
a = MaybeT [Just 1, Just 2, Nothing] :: MaybeT [] Int

f <*> a = [Nothing, Nothing, Nothing]

do
x <- f
y <- a
return (x y)

= [Nothing]

因此,似乎MaybeT的应用程序和Monad中存在不一致。
如果有不和谐的话,我们怎么能把〉〉,〉,〉〉= .(〈〉)弄混呢?
真不敢相信,如果有这样的出入,那么目前使用MaybeT的众多Haskell代码中,不应该存在bug吗?

z9smfwbn

z9smfwbn1#

引用一条评论:
MaybeT(<*>)Compose m Maybe不同
的确:

ghci> import Data.Functor.Compose 
ghci> import Control.Monad.Trans.Maybe 
ghci> f = MaybeT [Nothing] :: MaybeT [] (Int -> Int)
ghci> a = MaybeT [Just 1, Just 2, Nothing] :: MaybeT [] Int
ghci> f <*> a
MaybeT [Nothing]
ghci> Compose (runMaybeT f) <*> Compose (runMaybeT a)
Compose [Nothing,Nothing,Nothing]

至于它们的区别,(<*>)对于Compose定义为:

Compose u <*> Compose v = Compose (liftA2 (<*>) u v)
  • 如果 * 被组合的两个应用函子也是monad(如[]Maybe),我们可以用它们的monad示例来表示:
Compose (liftA2 (<*>) u v)

Compose $ do
    ui <- u  -- "i" is for "inner"
    vi <- v
    return (ui <*> vi)

Compose $ do
    ui <- u
    vi <- v
    return $ do
        f <- ui
        a <- vi
        return (f a)

其中,内部函子为Maybe,变为:

Compose $ do
    ui <- u
    vi <- v
    return $ do
        f <- ui
        a <- vi
        Just (f a)

(<*>)对于MaybeT

mf <*> mx = MaybeT $ do
    mb_f <- runMaybeT mf
    case mb_f of
        Nothing -> return Nothing
        Just f  -> do
            mb_x <- runMaybeT mx
            case mb_x of
                Nothing -> return Nothing
                Just x  -> return (Just (f x))

让我们用更接近上面的风格来重新表述右手边:

MaybeT u <*> MaybeT v = MaybeT $ do
    ui <- u
    case ui of
        Nothing -> return Nothing
        Just f  -> do
            vi <- v
            case vi of
                Nothing -> return Nothing
                Just x  -> return (Just (f x))

(<*>) for Compose在内部效果之前运行外部效果,因此在您的示例中,您将在外部级别获得通常的列表(<*>),获得1 * 3 = 3个元素的列表。运行其第一个参数的效果(外部和内部Maybe),然后移动到第二个,并且只有当获得Just时,因此,在你的例子中,Nothing位于f中,只会产生另一个Nothing,最终得到[Nothing]

flvlnr44

flvlnr442#

正如评论中提到的,问题有一个假前提,问题中的两个表述

f <*> a

do
  x <- f
  y <- a
  return (x y)

两者产生相同的结果MaybeT [Nothing]
你不应该在自然界中找到这两个表达式对于一个类型不同的例子。

m1 <*> m2 = m1 >>= (\x1 -> m2 >>= (\x2 -> return (x1 x2)))

这只是对你试图反驳的身份的去糖化。可能有一些单子的例子违反了这条定律,但它们不是“应该”这样做。

相关问题