6

以下代码是否使用 C++ 或 Java 中所理解的动态调度?

据我了解,在最后一行,编译器不可能在编译时知道要调用 (==) 的哪个实现,但是代码可以编译并产生正确的结果。有人可以解释一下,这背后有什么样的实现(例如vptr)?

{-# LANGUAGE ExistentialQuantification #-}

data Value = A Int

data ForallFunc = forall a. Eq a => Forall (Value -> a) 

unpackA (A int) = int

equalityTest :: Value -> Value -> ForallFunc -> Bool            
equalityTest arg1 arg2 (Forall unpacker) =
  let a1 = unpacker arg1
      a2 = unpacker arg2 in
    a1 == a2
4

2 回答 2

8

大致,是的。

当您使用有存在量化时,即当量化类型变量受到某些约束时C a => ...,GHC 将在构造函数中存储一些指针,记住它们的方法,C a以便以后可以在您进行模式匹配时访问它们那个构造函数。

通常使用单个指针,很像许多 OOP 实现vptr中的 a vtable。编译器也可以直接存储指向方法的指针,避免间接。我认为当类型类中只有一种方法时,这是由 GHC 完成的。当方法很少(比如两个)时也可以使用它——这会使每个值的内存占用更大,但访问速度更快。

所以,编译你的代码就像用Eq字典替换约束一样粗略地完成,列出它的方法。那是:

data EqDict a = EqDict
   { eq  :: a->a->Bool
   , neq :: a->a->Bool }

data ForallFunc = forall a. Forall (EqDict a) (Value -> a) 

unpackA (A int) = int

equalityTest :: Value -> Value -> ForallFunc -> Bool            
equalityTest arg1 arg2 (Forall eqDict unpacker) =
  let a1 = unpacker arg1
      a2 = unpacker arg2 in
    eq eqDict a1 a2

当然,编译构造函数调用Forall someFunction大致是通过提供所需函数的实现来编译的,==它们/=的特定类型将被存在量化抽象掉。

于 2018-04-22T07:54:19.583 回答
5

是的,ghc 使用一种动态调度的形式。Eq a约束意味着 for 的表示将ForallFunc包含一个字典(对应于一个 vtable),它在运行时用于调用正确的相等函数。

于 2018-04-22T07:57:24.963 回答