我刚刚阅读了row polymorphism以及它如何用于可扩展记录和多态变体。
然而,Ocaml使用子类型进行多态变体。为什么?它比行多态更强大吗?
答案 0 :(得分:11)
OCaml使用行行多态和子类型来处理多态变体(以及对象)。行开放多态性涉及“开放”对象类型< m1 : t1; m2 : t2; .. >
(..
实际上是类型的一部分)或“开放”变体类型[> `K1 of t1 | `K2 of t2 ]
。子类型用于在封闭的非多态类型<m1:t1; m2:t2> :> <m1:t1>
或[ `K1 of t1 ] :> [ `K1 of t1 | `K2 of t2 ]
之间进行投射。
行多态允许避免使用有界量化来表达类型,例如“获取至少具有方法m
的对象,并返回相同类型的对象”:因此子类型非常简单,显式的,不能抽象的。相反,行多态更容易推断,并且与类型系统的其余部分一起将更好地发挥作用。应该很少需要使用闭合类型和显式子类型,但偶尔会很方便 - 特别是保持类型关闭会产生更容易理解的错误消息。
答案 1 :(得分:6)
为了补充Gabriel的答案,考虑这一点的一种方法是子类型提供了通用和存在多态的弱形式。当参数多态的两个方向都可用时,子类型的表达性大部分被包含(特别是当没有深度子类型时)。但Ocaml的情况并非如此。
Ocaml通过实际的通用多态性取代了通用方面,但保留了子类型,为您提供了一种存在量化的形式,否则它就没有了。这需要形成例如异构集合,例如<a: int> list
,您希望在其中存储至少具有正确类型的a
方法的任意对象。
我会更进一步地说,虽然这通常被解释为Ocaml世界中的子类型,但可能实际上将闭合行解释为在(未知)尾部上存在量化。通过:>
强制将是存在性引入,从而更加忠实于构建行的参数多态的世界。 (当然,根据这种解释,#
会隐式存在性消除。)如果我从头开始设计类似Ocaml的系统,我可能会尝试以这种方式对其进行建模。