匹配 MaybeT 的 Monad 和 Applicative 的上下文:我实际上找到了一个反例。

huangapple go评论125阅读模式
英文:

Match the context of MaybeT's Monad and Applicative: I actually found a counter-example

问题

I had a hard time finding out if MaybeT's Monad and Applicative have the same context. As you can see in the link above.

"same context" 的意思是

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

我很难确定 MaybeT 的 Monad 和 Applicative 是否具有相同的上下文。正如您在上面的链接中所看到的。

"相同的上下文" 是指:

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

I found a counter-example for MaybeT.

我找到了 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]

So, it seems like there's a discord in MaybeT's Applicative and Monad.

因此,看起来 MaybeT 的 Applicative 和 Monad 存在不一致。

How could we mix up >>, >, >>=, (<>) if there is a discord?

如果存在不一致,我们该如何混合使用 >>、>、>>=、(<>)?

I can't believe it. If there is such a discrepancy, shouldn't there be a bug in the many Haskell codes currently using MaybeT?

我难以相信。如果存在这样的不一致,那么目前使用 MaybeT 的许多 Haskell 代码中应该存在错误吗?

英文:

https://stackoverflow.com/questions/76032068/i-wonder-if-applicative-is-derived-naturally-through-monadtransformers-monad

I had a hard time finding out if MaybeT's Monad and Applicative have the same context. As you can see in the link above.

The meaning of "same context" is

f &lt;*&gt; a = do
          x &lt;- f
          y &lt;- a
          return (x y)

I found a counter-example for MaybeT.

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

f &lt;*&gt; a = [Nothing, Nothing, Nothing]

do
x &lt;- f
y &lt;- a
return (x y)

= [Nothing]

So,
it seems like there's a discord in MaybeT's Applicative and Monad.

How could we mix up >> , > , >>= . (<>) if there is a discord?

I can't believe it.
If there is such a discrepancy, shouldn't there be a bug in the many Haskell codes currently using MaybeT?

答案1

得分: 4

以下是您要翻译的内容:

引述一条评论:

> MaybeT(&lt;*&gt;)Compose m Maybe 不同

确实:

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

至于它们的区别,Compose(&lt;*&gt;) 定义如下

Compose u &lt;*&gt; Compose v = Compose (liftA2 (&lt;*&gt;) u v)

如果 被组合的两个应用函子也是单子(就像 []Maybe 一样),我们可以根据它们的单子实例来表达:

Compose (liftA2 (&lt;*&gt;) u v)

Compose $ do
    ui &lt;- u  -- “i” 是“内部”的意思
    vi &lt;- v
    return (ui &lt;*&gt; vi)

Compose $ do
    ui &lt;- u
    vi &lt;- v
    return $ do
        f &lt;- ui
        a &lt;- vi
        return (f a)

而对于内部函子是 Maybe 的情况,变成了:

Compose $ do
    ui &lt;- u
    vi &lt;- v
    return $ do
        f &lt;- ui
        a &lt;- vi
        Just (f a)

MaybeT(&lt;*&gt;) 是:

mf &lt;*&gt; mx = MaybeT $ do
    mb_f &lt;- runMaybeT mf
    case mb_f of
        Nothing -&gt; return Nothing
        Just f  -&gt; do
            mb_x &lt;- runMaybeT mx
            case mb_x of
                Nothing -&gt; return Nothing
                Just x  -&gt; return (Just (f x))

让我们以接近上述样式的方式重新表述右边的内容:

MaybeT u &lt;*&gt; MaybeT v = MaybeT $ do
    ui &lt;- u
    case ui of
        Nothing -&gt; return Nothing
        Just f  -&gt; do
            vi &lt;- v
            case vi of
                Nothing -&gt; return Nothing
                Just x  -&gt; return (Just (f x))

Compose(&lt;*&gt;) 在运行外部效果之前运行内部效果,因此在您的示例中,您得到了通常的列表 (&lt;*&gt;) 在外部级别运行,获得了一个由1 * 3 = 3个元素组成的列表。然而,MaybeT(&lt;*&gt;) 运行其第一个参数(外部和内部的 Maybe)的效果,然后才转向第二个参数,仅在获得 Just 时才这样做,因此在您的示例中,f 中的 Nothing 仅产生另一个 Nothing,最终导致 [Nothing]

英文:

Quoting a comment:

> MaybeT's (&lt;*&gt;) is different from Compose m Maybe

Indeed:

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

As for how they differ, (&lt;*&gt;) for Compose is defined as:

Compose u &lt;*&gt; Compose v = Compose (liftA2 (&lt;*&gt;) u v)

If the two applicative functors being composed are also monads (as [] and Maybe are), we can express that in terms of their monad instances:

Compose (liftA2 (&lt;*&gt;) u v)

Compose $ do
    ui &lt;- u  -- &quot;i&quot; is for &quot;inner&quot;
    vi &lt;- v
    return (ui &lt;*&gt; vi)

Compose $ do
    ui &lt;- u
    vi &lt;- v
    return $ do
        f &lt;- ui
        a &lt;- vi
        return (f a)

Which, with the inner functor being Maybe, becomes:

Compose $ do
    ui &lt;- u
    vi &lt;- v
    return $ do
        f &lt;- ui
        a &lt;- vi
        Just (f a)

Whereas (&lt;*&gt;) for MaybeT is

mf &lt;*&gt; mx = MaybeT $ do
    mb_f &lt;- runMaybeT mf
    case mb_f of
        Nothing -&gt; return Nothing
        Just f  -&gt; do
            mb_x &lt;- runMaybeT mx
            case mb_x of
                Nothing -&gt; return Nothing
                Just x  -&gt; return (Just (f x))

Let's rephrase the right-hand side in a style closer to the one above:

MaybeT u &lt;*&gt; MaybeT v = MaybeT $ do
    ui &lt;- u
    case ui of
        Nothing -&gt; return Nothing
        Just f  -&gt; do
            vi &lt;- v
            case vi of
                Nothing -&gt; return Nothing
                Just x  -&gt; return (Just (f x))

(&lt;*&gt;) for Compose runs the outer effects before the inner ones, and so in your example you get the usual list (&lt;*&gt;) at the outer level, obtaining a list of 1 * 3 = 3 elements. (&lt;*&gt;) for MaybeT, however, runs the effects of its first argument (both the outer and the inner Maybe) before moving on to the second one, and that only if a Just is obtained, and so the Nothing lying in f in your example gives rise to merely another Nothing, resulting in [Nothing] overall.

答案2

得分: 2

As mentioned in the comments, the question has a false premise. The two expressions in the question,

f <*> a

and

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

both produce the same result, MaybeT [Nothing].

You shouldn't be able to find examples in the wild where these two expressions differ for a single type. One of the laws listed in the Monad class is

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

which is just a desugaring of the identity you're trying to disprove. There are probably some examples out there of monads that break this law, but they're not "supposed" to.

英文:

As mentioned in the comments, the question has a false premise. The two expressions in the question,

f &lt;*&gt; a

and

do
  x &lt;- f
  y &lt;- a
  return (x y)

both produce the same result, MaybeT [Nothing].

You shouldn't be able to find examples in the wild where these two expressions differ for a single type. One of the laws listed in the Monad class is

m1 &lt;*&gt; m2 = m1 &gt;&gt;= (\x1 -&gt; m2 &gt;&gt;= (\x2 -&gt; return (x1 x2)))

which is just a desugaring of the identity you're trying to disprove. There are probably some examples out there of monads that break this law, but they're not "supposed" to.

huangapple
  • 本文由 发表于 2023年4月17日 20:21:29
  • 转载请务必保留本文链接:https://go.coder-hub.com/76035115.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定