问题描述
此示例适用于ghci,加载此文件:
import Safe
t1 = tailMay []
并放入ghci:
> print t1
nothing
但是,如果我们在以前的文件中添加类似的定义,那么它将不起作用:
import Safe
t1 = tailMay []
t2 = print $ tailMay []
出现这样的错误:
* Ambiguous type variable `a0' arising from a use of `print'
prevents the constraint `(Show a0)' from being solved.
Probable fix: use a type annotation to specify what `a0' should be.
These potential instances exist:
instance Show Ordering -- Defined in `GHC.Show'
instance Show Integer -- Defined in `GHC.Show'
instance Show a => Show (Maybe a) -- Defined in `GHC.Show'
...plus 22 others
这是ghc的第三个样本,具有相同的错误:
import Safe
t1 = tailMay
main = do
print $ t1 []
print $ t1 [1,2,3]
为什么?以及如何在没有显式类型注释的情况下修复第二个示例?
解决方法
这里的问题是tailMay []
可以为任何Maybe [a]
生成类型为a
的输出,而print
可以为以下类型生成Maybe [a]
的输入任何a
(在Show
类中)。
当您组成“通用生产者”和“通用使用者”时,编译器不知道选择哪种类型a
-可以是类Show
中的任何类型。选择a
可能很重要,因为原则上print (Nothing :: Maybe [Int])
可以打印出与print (Nothing :: Maybe [Bool])
不同的内容。在这种情况下,打印的输出将是相同的,但这仅仅是因为我们很幸运。
例如,print ([] :: [Int])
和print ([] :: [Char])
将打印不同的消息,因此print []
是不明确的。因此,GHC拒绝了它,并需要显式类型注释(或使用扩展名的类型应用程序@ type
)。
那么,为什么GHCi会接受这种歧义?嗯,GHCi旨在用于快速实验,因此,作为一种便利功能,它将努力默认这些不明确的a
。这是使用extended defaulting rules完成的,(我猜)原则上也可以通过打开该扩展名在GHC中将其打开。
但是,不建议这样做,因为有时默认规则可能会选择一些意外类型,从而使代码可以编译,但会产生有害的运行时行为。
此问题的常见解决方案是使用批注(或@ type
),因为它为程序员提供了更多控制权,使代码更易于阅读,并且避免了意外。