我想我找到了一个“不存在的单子”

Posted

技术标签:

【中文标题】我想我找到了一个“不存在的单子”【英文标题】:I think I found a "non-existent monad" 【发布时间】:2019-09-12 02:53:38 【问题描述】:

我发现了 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 可以是任何单子。我的理论是这样的:因为return 1 的计算结果仅仅是1,所以return 1 可以被认为是1 提升到一个包裹在 "non-existent" monad 中的值. Haskell 捕捉到了这一事实并评估了整个表达式

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

False,因为它必须产生一个“不存在的False,它只是一个False

但是,我以前从未听说过这样的 “不存在” 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

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

【问题讨论】:

另见What is the default type evaluation of MonadPlus in Haskell?。 【参考方案1】:

return 1 不仅仅是1。您认为“不存在的单子”实际上是IO。当您使用return 1 时,GHCi 假设您的意思是IO,然后帮助执行 IO 表达式并显示结果。 1 &gt;&gt;= ... 会出现类型错误,因为 1 不是 monad。

正如@bradrn 提到in the comments,一般来说,GHCi 会自动运行您给它的任何 IO a 值,然后打印出 it 返回的值;如果你给 GHCi 一个非IO 类型的值,它只会打印那个值(如果可以的话)。

顺便说一句,有一个名为 Identity 的 monad,正如你所说的,它本质上是作为“不存在的 monad”工作的,因为无论你在其中添加什么,return x 都与 x 同构.但是,它不会自动使用。您需要手动包装和打开它才能使用它。

【讨论】:

我认为您的回答解释了我观察到的另一种行为:GHCI 对return (Just 1)Just 1 &gt;&gt;= return 显示相同的结果。前一个表达式本身的计算结果为IO (Just 1),并显示为Just 1,因为它被IO monad 包裹。在后一种情况下,表达式评估为Just 1,GHCI 只是将值打印出来。 这是正确的@Namudon'tdie。一般来说,GHCi 会自动运行你给它的任何IO a 值,然后打印出它返回的值;如果你给它一个非IO 类型,它只会打印结果(如果可以的话)。

以上是关于我想我找到了一个“不存在的单子”的主要内容,如果未能解决你的问题,请参考以下文章

Angular 6 的路由不适用于“Router”模块,我想我有一个错误但我不知道它是啥

非常简单的素数测试 - 我想我不理解for循环

sql查找ID并在没有找到结果时插入

AWS Cloudformation遇到不受支持的属性类型

我想我需要一个简单的规则引擎? [关闭]

适用于 iOS 的 Google Place API