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

时间:2019-01-02 02:52:21

标签: haskell instance

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

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实例列表中选择第一个实例,因为从理论上讲,这无关紧要(只要该实例的代数属性正确实现...)

1 个答案:

答案 0 :(得分:9)

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

  

表达式[..]不明确,因为文字4是Haskell中的Num a =>类型。 4可以是Int,Float或作为Num实例的任何其他类型,因此出于上述相同原因,编译器无法选择任何特定类型。但是Haskell委员会认为这是太多限制。经过大量辩论,他们妥协并添加了一个临时规则来选择特定的默认类型。

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