Haskell 类型神秘。这段代码为什么要编译?
代码Haskell 类型神秘。这段代码为什么要编译?,haskell,polymorphism,type-inference,ambiguity,Haskell,Polymorphism,Type Inference,Ambiguity,代码 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,我们都保证选择了
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
(或者我们的自定义类型在编译时同时具有分数
和Eq
)的实例,因此不存在歧义
但这只是一种感觉,我不知道它是否100%准确。本文中对歧义的定义如下: 我们说一个表达式
e
有一个不明确的类型,如果在它的类型forall.cx=>t
中,在us
中有一个类型变量u
,它出现在cx
中,但不出现在t
中。这种类型是无效的
在foo::(分数a,等式a)=>a->Bool
中没有这样的变量(因为a
出现在a->Bool
中)。在1.0==1.0
中,类型实际上是(分数a,等式a)=>Bool
,因此存在这样的变量
这种歧义之所以是错误的,是因为编译器无法在变量
a
的不同实例化之间进行选择,并且程序的结果可能取决于它选择的实例化。在这种情况下,对于任何合理的实例化,1.0==1.0
应始终为True
,但1)编译器不知道这一点;2) 并非所有的实例化都是合理的 第二段代码编译是因为
foo :: (Fractional a, Eq a) => a -> Bool
foo x = x == 1.0
(==) :: Eq a => a -> a
因此,编译器将知道浮点数文本1.0::Rational a=>a
与x
具有相同的类型,后者具有Eq
实例,即此函数中==
的“含义”对于每个调用都是确定的
而在第一段代码中,文字可以是任何类型的
(有理a,等式a)=>a
,因此==
的“含义”是不明确的,h的值可以是真的也可以是假的,取决于文字的类型,这是没有提供的。这里有另一种概念性的说法:
这两种情况都有内在的歧义,但第一种情况是死路一条——编译器没有希望推断出摆脱歧义的方法
第二种情况也是不明确的,但不明确是公开的——无论谁调用不明确的代码,都必须解决不明确的问题,或者在调用堆栈中进一步委托/冒泡它
这就是它的全部——多态性是受控的模糊性。第一种情况是不受控制的歧义,因此它不是有用的(即多态性相关的)歧义。所以它会被拒绝,直到它被注释为明确无误 @Carsten两者都在
Eq
,这一点都不重要;这是非法的,因为选择其中一个可能会给出与另一个不同的结果(对于这个程序,它当然不会,但编译器不知道,也不应该知道)。@AlexeyRomanov很抱歉……你能仔细地说一下为什么这不是一个复制的吗?