为什么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
我们可以将两种不同的类型 s1
和 s2
分配给表达式 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)
我们很容易看出s1
和s2
都是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 succ
或 choose id auto
那么它在论文中是不完整的。
P.S。其他直觉来源:这个问题基本上对应于解析中的 shift/reduce 冲突,或 lazy/eager 评估。事实上,我们需要决定是立即实例化类型应用程序还是进一步延迟它,而且这两种选择都不比另一种更普遍。由于有时急切的实例化会启用表达式的类型(例如,将 s1
归因于 auto
),有时延迟会破坏类型系统(通过将 s2
归因于 auto
,从而启用 auto succ
)
我正在研究基于论文 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
我们可以将两种不同的类型 s1
和 s2
分配给表达式 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)
我们很容易看出s1
和s2
都是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 succ
或 choose id auto
那么它在论文中是不完整的。
P.S。其他直觉来源:这个问题基本上对应于解析中的 shift/reduce 冲突,或 lazy/eager 评估。事实上,我们需要决定是立即实例化类型应用程序还是进一步延迟它,而且这两种选择都不比另一种更普遍。由于有时急切的实例化会启用表达式的类型(例如,将 s1
归因于 auto
),有时延迟会破坏类型系统(通过将 s2
归因于 auto
,从而启用 auto succ
)