我想我找到了 "non-existent monad"

I think I found a "non-existent monad"

我发现了 Haskell 的一个奇怪特征,这让我相信我的思考方式是错误的。我认为在 Haskell 中应该有一些 "non-existent" monad。这是因为以下原因。

Prelude> return 1
1
Prelude> return 1 >>= \x -> if even x then return True else return False
False

>>=m a -> (a -> m b) -> m b 类型,其中 m 可以是任何 monad。我的理论是这样的:由于 return 1 的计算结果仅为 1,因此 return 1 可以被认为是 1 提升到包含在 中的值"non-existent" 单子。 Haskell 捕获了这个事实并评估了整个表达式

return 1 >>= \x -> if even x then return True else return False

False 因为它必须产生一个 "non-existent False" 这仅仅是 False.

但是,我以前从未听说过这样的 "non-existent" monad。

我确信我以错误的方式对它进行了理论化,因为如果 "non-existent 1" 只是 1,则以下表达式必须类型一致,但事实并非如此。它是上述版本的修改版本。

1 >>= \x -> if even x then return True else return False

<interactive>:57:1: error:
    • Could not deduce (Integral a0)
      from the context: (Monad m, Integral a, Num (m a))
        bound by the inferred type for ‘it’:
                   forall (m :: * -> *) a. (Monad m, Integral a, Num (m a)) => m Bool
        at <interactive>:57:1-56
      The type variable ‘a0’ is ambiguous
    • In the ambiguity check for the inferred type for ‘it’
      To defer the ambiguity check to use sites, enable AllowAmbiguousTypes
      When checking the inferred type
        it :: forall (m :: * -> *) a.
              (Monad m, Integral a, Num (m a)) =>
              m Bool

所以,我的理论肯定有矛盾。我错过了什么?

return 1 不仅仅是 1。你认为的 "non-existent monad" 实际上是 IO。当您使用 return 1 时,GHCi 假设您的意思是 IO,然后帮助执行 IO 表达式并显示结果。 1 >>= ... 出现类型错误,因为 1 不是 monad。

作为@bradrn mentions ,一般来说GHCi会自动运行你给它的任何IO a值,然后打印出这个值 returns;如果你给 GHCi 一个非 IO 类型的值,它只会打印那个值(如果可以的话)。

顺便说一句,有一个名为 Identity 的 monad,正如您所说,它本质上确实像 "non-existent monad" 一样工作,因为 return xx 同构不管你放什么。但是,它不会自动使用;您需要手动包装和解包才能使用它。