正如 Don Stewart 所说,GHC 中的类型类是使用“字典”实现的。这意味着类型类Num
被表示为函数的记录(我将跳过Eq
and Show
此处的限制):
class Num a where
fromInteger :: Integer -> a
...
becomes
data Num a = Num { fromInteger :: Integer -> a, ... }
定义实例时,将使用该实例中的函数创建一条新记录:
instance Num Integer where
fromInteger = id
...
becomes
numDictForInteger = Num { fromInteger = id, ... }
现在,当您在多态上下文中使用此函数时,编译器不知道要使用哪个字典,因此它会为其生成一个额外的参数:
foo :: Num a => a
foo = 1
becomes
foo :: Num a -> a
foo numDict = fromInteger numDict 1
注意如何约束Num a =>
成为参数Num a ->
.
但是,当您删除多态性时,编译器知道要静态使用哪个字典,因此它会继续内联它而不是生成参数:
foo :: Integer
foo = 1
becomes
foo :: Integer
foo = fromInteger numDictForInteger 1
作为脚注,这就是单态限制存在的原因。多态值不会是 CAF,因为它需要字典参数。这可能会导致性能特征与您预期的显着不同,因此您必须明确声明此行为是您想要的。