输入奥秘。为什么这段代码会编译?

时间:2016-01-18 13:24:09

标签: haskell polymorphism type-inference ambiguity

代码

default ()
h :: Bool
h = 1.0 == 1.0 --Error. Ambiguity.

无法编译。这是预料之中的,因为存在歧义。它可以是FloatDouble,而Haskell也不知道我们想要哪一个。

但代码

default ()
foo :: (Fractional a, Eq a) => a -> Bool
foo x = x == 1.0

成功编译。我不完全明白为什么。为什么这也不明确?

我觉得这是因为每当我们致电foo时,我们都会保证选择具体类型代替a,即我们保证已经修复a在编译时,FloatDouble(或我们的自定义类型,包含FractionalEq的实例),因此没有歧义。

但这只是一种感觉,我不知道它是否100%准确。

3 个答案:

答案 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 => ax具有相同的类型,其中Eq实例即==的“含义”每个电话都有此功能。

在第一段代码中,文字可以是任何类型(Rational a, Eq a) => a,因此==的“含义”是不明确的,h的值可以是True或False,取决于文字的类型,没有提供。

答案 2 :(得分:0)

这里是另一个概念性的方式:

这两种情况都有内在的模糊性,但第一种情况是死路一条 - 编译器没有希望从模糊性中推断出它的出路。

第二种情况也是含糊不清的,但歧义是开放的 - 无论谁调用模糊代码,都必须解决歧义,或者在调用堆栈中进一步委托/冒泡。

这就是它的全部 - 多态性是受控制的模糊性。第一种情况是不受控制的歧义,因此它没有用处(即与多态相关的)模糊性。所以它被拒绝,直到它被注释为明确无误。