GHC 是否对存在类型使用动态调度?
Does GHC use dynamic dispatch with existential types?
以下代码是否使用了 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
大致是这样。
当你使用有界存在量化时,即当量化类型变量受到某些约束C a => ...
的限制时,GHC将在构造函数,记住 C a
的方法,以便以后在该构造函数上进行模式匹配时可以访问它们。
通常使用单个指针,很像许多 OOP 实现中的 vptr
到 vtable
。编译器也可以直接存储指向方法的指针,避免间接访问。我认为这是在 class 类型中只有一种方法时由 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
是编译,大致是通过为需要的==
、/=
函数提供实现,在它们的特定类型上进行抽象远离存在量化。
是的,ghc 使用了一种动态调度的形式。 Eq a
约束意味着 ForallFunc
的表示将包含一个字典(对应于一个 vtable),它在运行时用于调用右等式函数。
以下代码是否使用了 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
大致是这样。
当你使用有界存在量化时,即当量化类型变量受到某些约束C a => ...
的限制时,GHC将在构造函数,记住 C a
的方法,以便以后在该构造函数上进行模式匹配时可以访问它们。
通常使用单个指针,很像许多 OOP 实现中的 vptr
到 vtable
。编译器也可以直接存储指向方法的指针,避免间接访问。我认为这是在 class 类型中只有一种方法时由 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
是编译,大致是通过为需要的==
、/=
函数提供实现,在它们的特定类型上进行抽象远离存在量化。
是的,ghc 使用了一种动态调度的形式。 Eq a
约束意味着 ForallFunc
的表示将包含一个字典(对应于一个 vtable),它在运行时用于调用右等式函数。