为什么MLF中有灵活和严格的界限?

Why are there flexible and rigid bounds in MLF?

我正在研究基于论文 Raising ML to the Power of System F 的 MLF 实现。在论文中类型定义为:

t ::= a | g t1 ... tn
o ::= t | ⊥ | ∀(a ≥ o) o | ∀(a = o) o

我无法理解 ≥ 和 = 在类型构造方面的区别?专为统一算法。

我在附录中实现了统一和推理算法,这种方式似乎可以维护这些算法的所有不变量,而无需以有意义的方式读取绑定类型。

我想要一个例子,说明统一的结果何时会根据绑定的种类而变化。

在论文的"Our track"部分有详细描述。我将尝试提供一种不同的、不太正式的解释,希望能帮助您建立自己的直觉。

基本上,刚性绑定类型变量是 ML 弱变量的 MLF 版本。可以使用论文中的示例来说明。给定函数

choose x y = if true then x else y

我们可以将两种不同的类型 s1s2 分配给表达式 choose id,它们的区别仅在于我们量化类型变量的方式

 s1 = \forall a. ((a -> a) -> (a -> a))
 s2 = (\forall a. (a -> a)) -> (\forall a. (a -> a))

显然,在 MLF 中,这两种类型都不比另一种更通用,因此我们不得不通过引入灵活的类型来延迟选择一个或另一个,并给出 choose id 以下类型

 s3 = (\forall a. a >= (\forall a. a -> a)). (a -> a) 

我们很容易看出s1s2都是s3的实例。

auto (x : \forall a. a -> a) = x x 函数被用作试金石,它显示了一个函数示例,该函数无法被赋予灵活类型,因为它可以被赋予 s2 类型,其类型很好auto succ as (int -> int) -> (int -> int) 这显然会破坏我们的类型系统(即,我们可以应用 succ succ)。因此,我们需要给出一个具有刚性边界的较弱类型,

 s4 = (\forall a. a = (\forall a. a -> a)). (a -> a) 

因此,如果您的实施允许 auto succ,那么它就不合理了。如果它不允许 choose id succchoose id auto 那么它在论文中是不完整的。

P.S。其他直觉来源:这个问题基本上对应于解析中的 shift/reduce 冲突,或 lazy/eager 评估。事实上,我们需要决定是立即实例化类型应用程序还是进一步延迟它,而且这两种选择都不比另一种更普遍。由于有时急切的实例化会启用表达式的类型(例如,将 s1 归因于 auto),有时延迟会破坏类型系统(通过将 s2 归因于 auto,从而启用 auto succ)