我想我找到了一个“不存在的单子”
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 >>= ...
会出现类型错误,因为 1
不是 monad。
正如@bradrn 提到in the comments,一般来说,GHCi 会自动运行您给它的任何 IO a
值,然后打印出 it 返回的值;如果你给 GHCi 一个非IO
类型的值,它只会打印那个值(如果可以的话)。
顺便说一句,有一个名为 Identity
的 monad,正如你所说的,它本质上是作为“不存在的 monad”工作的,因为无论你在其中添加什么,return x
都与 x
同构.但是,它不会自动使用。您需要手动包装和打开它才能使用它。
【讨论】:
我认为您的回答解释了我观察到的另一种行为:GHCI 对return (Just 1)
和Just 1 >>= return
显示相同的结果。前一个表达式本身的计算结果为IO (Just 1)
,并显示为Just 1
,因为它被IO
monad 包裹。在后一种情况下,表达式评估为Just 1
,GHCI 只是将值打印出来。
这是正确的@Namudon'tdie。一般来说,GHCi 会自动运行你给它的任何IO a
值,然后打印出它返回的值;如果你给它一个非IO
类型,它只会打印结果(如果可以的话)。以上是关于我想我找到了一个“不存在的单子”的主要内容,如果未能解决你的问题,请参考以下文章