代码
default ()
h :: Bool
h = 1.0 == 1.0 --Error. Ambiguity.
无法编译。这是预料之中的,因为存在歧义。它可以是Float
或Double
,而Haskell也不知道我们想要哪一个。
但代码
default ()
foo :: (Fractional a, Eq a) => a -> Bool
foo x = x == 1.0
成功编译。我不完全明白为什么。为什么这也不明确?
我觉得这是因为每当我们致电foo
时,我们都会保证选择具体类型代替a
,即我们保证已经修复a
在编译时,Float
或Double
(或我们的自定义类型,包含Fractional
和Eq
的实例),因此没有歧义。
但这只是一种感觉,我不知道它是否100%准确。
答案 0 :(得分:10)
此上下文中歧义的定义在Section 4.3.4 of Haskell Report中给出:
我们说表达式
e
有一个不明确的类型,如果在forall us. cx => t
类型中,u
中的类型变量us
出现在{{1}中但不在cx
中。这些类型无效。
在t
中,没有此类变量(因为foo :: (Fractional a, Eq a) => a -> Bool
中出现a
)。在a -> Bool
中,类型实际上是1.0 == 1.0
,因此存在这样的变量。
原因这种歧义是一个错误,因为编译器无法在变量(Fractional a, Eq a) => Bool
的不同实例化之间进行选择,并且程序的结果可能依赖于它选择哪一个。在这种情况下,对于任何合理的实例化,a
应始终为1.0 == 1.0
,但1)编译器不知道这一点; 2)并非所有实例都是合理的。
答案 1 :(得分:4)
第二段代码编译是因为
foo :: (Fractional a, Eq a) => a -> Bool
foo x = x == 1.0
(==) :: Eq a => a -> a
因此编译器会知道浮点数文字1.0 :: Rational a => a
与x
具有相同的类型,其中Eq
实例即==
的“含义”每个电话都有此功能。
在第一段代码中,文字可以是任何类型(Rational a, Eq a) => a
,因此==
的“含义”是不明确的,h的值可以是True或False,取决于文字的类型,没有提供。
答案 2 :(得分:0)
这里是另一个概念性的方式:
这两种情况都有内在的模糊性,但第一种情况是死路一条 - 编译器没有希望从模糊性中推断出它的出路。
第二种情况也是含糊不清的,但歧义是开放的 - 无论谁调用模糊代码,都必须解决歧义,或者在调用堆栈中进一步委托/冒泡。
这就是它的全部 - 多态性是受控制的模糊性。第一种情况是不受控制的歧义,因此它没有用处(即与多态相关的)模糊性。所以它被拒绝,直到它被注释为明确无误。