这是一篇关于统合(unification,有人叫做「合一」,但是我不是很喜欢这个名字)的文章,有人想让我写因此我就写了。

统合在不同语境下的意思有一些微妙的区别。基本上,它涉及两个项之间的比较。最基本的比较的方法是确认两个项是否在定义上相等,这种方式有时候也被称为转换检查(conversion check);在复杂一些的系统中,统合会顺便尝试求解元变量(metavariable);更为推广的方法中,即使两个项并非在定义上相等,也可能会得出某个一般统合子(most general unifier)。

# 转换检查

转换检查可以用于确定两个项是否在定义上相等。这听起来是平凡的,例如,Pi 类型只可能与 Pi 类型相等。

那么,如果我们对于每个语法构造都写一条关于 的规则,是否就解决了?若我们定义环境内包含某个常量 ,那么 还是无解的,因为 的构造是「常量」而 的构造是「Pi 类型」。这提示我们应该添加一个新的定义。

并转而使用 ,将 留作内部使用。为下文行文方便,从现在开始我们把 称作 ,而把 称作

到此我们可以相似地定义 Sigma 类型的 规则(怎么做?)。

变量的规则同样很平凡。

我们来看应用的规则。注意到两边的项都是 WHNF,因此应用只可能是中性的(neutral),也就是说它的头部是不可化简的。这也就是说,它的头部是一个变量,或者是另一个中性的项。此时我们也只有确保它们结构相等的情况下才能说它们定义上相等。

根据上面提到的原则,我们可以相似地定义投影的 规则(怎么做?)。

对于 lambda 表达式,情况变得稍微有趣了一些。

不行哦。 里面, 并不包含 ;如果我们想加入 ,则必须要得知它的类型;而我们不知道。更糟糕的是,这样一条规则也没办法处理 eta 转换: 是无解的!

# 类型导向

在非类型层面上,我们需要引入类型导向的转换检查。我们定义关系 意为「在知晓 WHNF 都有类型 的情况下,对 进行转换检查」,并定义 为将 化简到 WHNF 后进行 。另外,我们将 关系增强为 ,意味着「对 进行转换检查并推导出它们共有的类型 」,并相应地更新 的定义。这也就是说, 中的类型是返回的,而 的类型是传入的。

重新定义 的过程比较无聊,例如 Pi 类型的规则被重写为这样。

变量的规则被重写为这样。

而应用的规则稍微有趣一些,它被重写为下面这样。

注意到: 的交互就发生在对析构规则的处理中。现在我们来看更有趣的部分,即我们到底如何使用 处理构造规则。

我们没有直接检查 lambda 这一构造;我们只是利用了 均有 Pi 类型这一事实。我们应用一个新的变量作为参数,这直接处理了 eta 变换;一个变量 应用参数后变成了 ,一个带有若干层 lambda 的等价项 应用参数后也变成了 ,问题解决。我们最后提供如何从 降级到 ,即从推断降级为检查

注:这条规则还有另外一个版本。

其中第二条前提理论上是冗余的,但我不知道这能不能更方便地解出类型中的元变量。

# 元变量

# 一般统合子

— This article is unfinished. —