Haskell中MonadPlus的默认类型评估是什么?

6

我有以下代码:

import Control.Monad

coin :: MonadPlus m => m Int
coin = return 0 `mplus` return 1

如果我在解释器上评估coin :: Maybe Int,它会输出Just 0。这很正常,因为Maybe的实现是MonadPlus的一个实例。
如果我在解释器上评估coin :: [Int],它会输出[0, 1],因为列表上的mplus实现是一个append
但是,如果我评估没有任何类型修饰符的coin,它会输出0。为什么?解释器将coin转换为哪种类型来评估它?
这段代码摘自:http://homes.sice.indiana.edu/ccshan/rational/S0956796811000189a.pdf
2个回答

9
是的,这是 ghci 中一个不太被记录的角落。当你在 ghci 中输入一个表达式时,它使用表达式的类型来决定要做什么:
1. `IO ()`:运行该操作,不进行其他任何操作。
2. `Show a => IO a`:运行该操作并 `print` 结果。
3. 其他任何 `IO a`:运行该操作,不进行其他任何操作。
4. 其他任何类型的表达式:用 `print` 将整个表达式包装起来。
它是如何确定一个表达式属于上述哪种类型的呢?很简单:它尝试将你的表达式类型与上述每个签名逐一统一,并解决所有产生的约束。(对于专家而言:这是扩展默认规则之外的额外工作!这也解释了为什么它似乎正在默认使用 m,即使标准默认规则和扩展默认规则都没有说明要使用什么默认值。)
因此,由于你的表达式与 `IO ()` 不一致,但与 `Show a => IO a` 一致,ghci 在统一过程中发现 `m ~ IO`(以及 `a ~ Int`),发现有一个 `MonadPlus IO`(以及一个 `Show Int`)实例来解决约束,然后运行你的操作并打印结果。

4

GHCi(但不是 GHC 的通用版本)在缺少指定特殊化多态类型构造函数为 IO 的签名时,会尽可能地将其特殊化。反过来,提示符下的 IO 操作被执行,并且其结果以单子方式绑定到 it 变量上,然后打印出来(即 do { it <- action; print it }),只要结果类型有 Show 实例(参见 Daniel Wagner 的答案)。更多详情请查看用户指南中的 提示符下的 I/O 操作it 变量 部分。

在您的具体情况下,恰好发现存在 IOMonadPlus 实例。由于 IOmplus 仅在第一个操作引发异常时才执行第二个操作,因此您会从中获得 return 0。下面是一个演示:

GHCi> readLn `mplus` readLn :: IO Integer
0
0
GHCi> readLn `mplus` readLn :: IO Integer
foo
1
1
GHCi> readLn `mplus` readLn :: IO Integer
foo
bar
*** Exception: user error (Prelude.readIO: no parse)

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接