Haskell 中 MonadPlus 的默认类型评估是什么?
What is the default type evaluation of MonadPlus in Haskell?
我有以下代码:
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
。为什么?解释器 'converts' coin
评估它是什么类型?
此代码摘自:http://homes.sice.indiana.edu/ccshan/rational/S0956796811000189a.pdf
GHCi(但不是一般的 GHC)将在没有签名指定的情况下,尽可能将多态类型构造函数专门化为 IO
。 IO
提示符处的操作依次被执行并将其结果单子绑定到 it
变量,然后只要有 [=] 就打印(即 do { it <- action; print it }
) 15=] 结果类型的实例(参见用户指南的 ). For more details, have a look at the I/O actions at the prompt and The it variable 部分。
在您的具体情况下,恰好 there is a MonadPlus
instance for IO
。你从它得到 return 0
因为 mplus
for IO
只有在第一个动作抛出异常时才执行第二个动作。一个演示:
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)
是的,这是 ghci 的一个没有很好记录的角落。当你在 ghci 中输入一个表达式时,它会使用表达式的类型来决定要做什么:
IO ()
:运行动作,什么都不做。
Show a => IO a
:运行 行动和 print
结果。
- 任何其他
IO a
: 运行 动作,什么都不做。
- 其他:用
print
. 包裹整个表达式
它如何决定一个事物属于这些类型中的哪一种?简单:它试图依次统一上述每个签名的表达式类型,并解决所有由此产生的约束。 (对于 cognoscenti:这是扩展默认规则的 补充 !这解释了为什么它似乎默认了 m
,即使既不是标准默认规则也不是扩展默认规则默认规则说明使用什么默认值。)
因此,由于您的表达式不与 IO ()
统一,但与 Show a => IO a
统一,ghci 在统一过程中发现 m ~ IO
(和 a ~ Int
),发现那里是一个 MonadPlus IO
(和一个 Show Int
)实例,用于解析约束、运行您的操作并打印结果。
我有以下代码:
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
。为什么?解释器 'converts' coin
评估它是什么类型?
此代码摘自:http://homes.sice.indiana.edu/ccshan/rational/S0956796811000189a.pdf
GHCi(但不是一般的 GHC)将在没有签名指定的情况下,尽可能将多态类型构造函数专门化为 IO
。 IO
提示符处的操作依次被执行并将其结果单子绑定到 it
变量,然后只要有 [=] 就打印(即 do { it <- action; print it }
) 15=] 结果类型的实例(参见用户指南的
在您的具体情况下,恰好 there is a MonadPlus
instance for IO
。你从它得到 return 0
因为 mplus
for IO
只有在第一个动作抛出异常时才执行第二个动作。一个演示:
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)
是的,这是 ghci 的一个没有很好记录的角落。当你在 ghci 中输入一个表达式时,它会使用表达式的类型来决定要做什么:
IO ()
:运行动作,什么都不做。Show a => IO a
:运行 行动和print
结果。- 任何其他
IO a
: 运行 动作,什么都不做。 - 其他:用
print
. 包裹整个表达式
它如何决定一个事物属于这些类型中的哪一种?简单:它试图依次统一上述每个签名的表达式类型,并解决所有由此产生的约束。 (对于 cognoscenti:这是扩展默认规则的 补充 !这解释了为什么它似乎默认了 m
,即使既不是标准默认规则也不是扩展默认规则默认规则说明使用什么默认值。)
因此,由于您的表达式不与 IO ()
统一,但与 Show a => IO a
统一,ghci 在统一过程中发现 m ~ IO
(和 a ~ Int
),发现那里是一个 MonadPlus IO
(和一个 Show Int
)实例,用于解析约束、运行您的操作并打印结果。