Identity Monad - Haskell 中的行为差异?

Identity Monad - Behaviour difference in Haskell?

我最近一直在 Haskell 中研究 Monads(对于这一切,我还是一个相对初学者)。 Identity Monad.

我遇到了一些有趣的行为(或者至少对我来说很有趣)

如果我写下面的函数:

let f = \x -> Identity 2 >>= \y -> x * y

然后做 :t 我得到 f :: Num b => Identity b -> Identity b。它推断 x 是一个 Identity (Num b)。我可以使用 6 调用该函数并得到结果 12.

但是,如果我像这样对 Maybe 进行同样的尝试:

let g = \x -> Just 2 >>= \y -> x * y

<interactive>:2096:5: error:
    • Non type-variable argument in the constraint: Num (Maybe b)
      (Use FlexibleContexts to permit this)
    • When checking the inferred type
        g :: forall b. Num (Maybe b) => Maybe b -> Maybe b

因此我需要明确地 return Maybe 或使用 return。所以我这样做:let g = \x -> Just 2 >>= \y -> return $ x * y.

一切正常。但是后来我想知道 Identity monad 发生了什么。

首先,我尝试添加显式 return 类型,如下所示:

let f = \x -> Identity 2 >>= \y -> Identity $ x * y

然后又做了 :t,我得到了 f :: Num b => b -> Identity b。这正是我第一次期待的。


这让我想知道它如何在没有 Identity $ 的情况下处理 x + y 如果它推断 xy 被包裹在一个 Identity。所以我尝试了以下方法:

Identity 5 + Identity 6 结果为 11

Identity 5 + 6 结果又是 11

不过,我尝试用 Maybe 做同样的事情,就像这样

Just 5 + Just 6

Just 5 + 6

我收到以下错误:

<interactive>:2116:1: error:
    • Non type-variable argument in the constraint: Num (Maybe a)
      (Use FlexibleContexts to permit this)
    • When checking the inferred type
        it :: forall a. (Num (Maybe a), Num a) => Maybe a

我试过 FlexibleContexts 但我刚收到以下错误:

<interactive>:2134:1: error:
    • No instance for (Num (Maybe a0)) arising from a use of ‘it’
    • In the first argument of ‘print’, namely ‘it’
      In a stmt of an interactive GHCi command: print it

我想知道是否有人可以阐明为什么 Identity monad 行为与 Maybe 不同?

还有可能使用 FlexibleContexts 来获得与 Maybe monad 相同的行为吗?到目前为止,我还无法让它工作。

这是因为 Identity 有一个 Num 实例而 Maybe 没有(您可以在 GHCi 中使用 :i 或查看 in the Hackage documentation).

因此,当您有 \x -> Identity 2 >>= \y -> x * y 时,* 实际上是 Identity aNum 实例中的 *(其中 a 本身就是一个 Num 实例,例如 IntDouble 等)。

此外,Haskell 中的数字文字是多态的:5 :: Num a => a,因此它们可以像任何 Num 实例一样运行,而不是仅限于特定实例(如 IntDouble)。这就是当您尝试类似 Identity 5 + 6 时发生的情况。 6 被推断为 Num a => Identity a 类型,因为 (+) :: Num a => a -> a -> a.

你可以更清楚地看到这一点:

ghci> :t 5
5 :: Num p => p
ghci> 5 :: Identity Int
Identity 5
ghci> 5 :: Maybe Int

<interactive>:12:1: error:
    • No instance for (Num (Maybe Int)) arising from the literal ‘5’
    • In the expression: 5 :: Maybe Int
      In an equation for ‘it’: it = 5 :: Maybe Int