当从未具体键入中间值时,Haskell 编译器如何为 `(==) (fromInteger 0) (fromInteger 0)` 发出代码?

How does the Haskell compiler emit code for `(==) (fromInteger 0) (fromInteger 0)` when the intermediary values are never concretely typed?

我的问题与类型 class 在类型不明确的中间值存在时的实例推导有关

Prelude> :t fromInteger 0
fromInteger 0 :: Num a => a
Prelude> :t (==)
(==) :: Eq a => a -> a -> Bool
Prelude> :t (==) (fromInteger 0)
(==) (fromInteger 0) :: (Eq a, Num a) => a -> Bool
Prelude> :t (==) (fromInteger 0) (fromInteger 1)
(==) (fromInteger 0) (fromInteger 1) :: Bool
Prelude> (==) (fromInteger 0) (fromInteger 1)
False

神奇!目前还不清楚 a 是如何或是否具体化的,但代码 运行 成功了!

根据类型推断规则,上面 a 表示的类型变量成功地相互统一,因为它们在不同术语之间具有兼容的 Num a 约束。但是,a 从不绑定到具体类型。我的问题是,在运行时,(==) 函数使用哪个实例字典(或专业化,等等)?

这是 Haskell 依赖简单二进制 memcmp 样式比较的情况吗?或者它可能只是选择了 Num 个实例列表中的第一个实例,因为理论上它应该无关紧要(只要该实例的代数属性得到正确实现...)

是的,defaulting 将其具体化,这几乎是您的第二个理论。

The expression [..] is ambiguous because the literal 4 is of Num a => a type in Haskell. 4 can be an Int, a Float or any other type that is an instance of Num, so the compiler can’t choose any particular type for the same reason above. But the Haskell Committee thought that this is too much restriction. After much debates, they compromised and added an ad-hoc rule for choosing a particular default type.

(尽管选择哪个实例很重要。例如,如果选择 Int,则 2^64 == 0True,但如果选择 Integer,则 False选择。Integer 在默认列表中排在第一位是有充分理由的。)