前言

是个人学习笔记,会有很多自己的理解和想法,可能有不准确甚至错误的地方。如有发现可以来嘲讽笔者!

由于类型论相关的术语翻译混乱或者难以翻译,有些术语会附上英文原文或直接使用英文。

尝试把笔记写成一篇浅显易懂的入门读物,因此可能很多在诸位认为不重要的地方会花很多笔墨详细解释,以帮助新人理解。

主要是一些入门的内容,以后可能会有类型论进阶学习笔记

前置知识

元语言和形式语言

……

相继演算

相继演算是一种形如

的记号,其中分子上是若干条条件(Premise),分母上是结论(Conclusion),旁边是这个演算的名字。它代表的含义是,当分子上的所有条件都成立的时候,分母上的结论成立。

这种记号在类型论的研究中被大量使用。

柯里化

……?

简单类型

无类型 演算

为什么会产生类型?

为了回答这个问题,我们现看看没有类型会发生什么。接下来我们会介绍无类型的 演算。说它没有类型也不准确,我们也可以看作它所有的东西共用一个类型。

演算中一个项(term)定义为 ,这是说一个项要么是一个单独的变量 ,要么是两个项的拼接 ,要么是形如 的形式。

拼接两个项被称为应用(application),它是左结合的,也就是说 代表

这种形式被称为抽象(abstrcation),其中 是一个变量, 是一个项。抽象和我们中学时期理解的函数很像,比如我们定义一个函数 ,我们传入一个参数 得到的 其实就是把 中的所有 换成了 ;而 ,也就是把 应用到这个项上,代表把项 中所有 都替换成 。注意我们一般规定抽象的优先级比应用要高,也就是 说的是 而不是

我们把 中的 全部替换成 的结果写成

-转换

我们刚刚知道了 演算的基本规则,那么请思考一个问题: 该怎么算?最后得到的是 还是 ?换言之我们第一步应用得到的 中的两个 是不是同一个

其实如果我们换一个变量名 就很清晰了。这个项毫无疑问等于 ,而我们直觉上认为, 是等价的东西,就像 没什么区别一样。事实上在 演算中也是这样规定的。我们接下来形式化地描述一下这种”重命名“的过程。

在一个项 中,只要不是在 的位置使用了一个变量 ,我们就称这个变量 在项 中出现(occurence)了。对于一个项 ,如果 这个项中出现了 ,那么这个项中的 就是一个绑定变量(bounded variable),否则是一个自由变量(bounded variable)。我们之前说的 严格定义是将 中所有自由的 换成

同时,我们认为将 中的 共同换成一个 中自由的变量,变换后的项和原来是等价的。这就是 -转换(-conversion)。显然地,我们可以把一个项的所有变量都转化为两两不同的变量,这样就不会出现我们上面草歧义。

而之所以我们出现了上面的歧义,是因为我们采用了字符串来代指数学对象,因此我们即使用着同样的名字 ,两个 想表达的意思却是不一样的,就会造成一些混淆。

规约和暨约形式

归约 (reduction) 主要描述了一个项怎么化简, 或者说计算。而暨约形式(normal form)则是经过化简得到的所谓“最简形式”。在基础的 演算中主要有两条规则:

这条规则告诉我们如何使用一个函数,正向使用这个规则叫做 -规约。

正向使用这个规则叫做 -展开,反向使用则叫 -规约。

这个规则看起来没什么必要,但是它其实向我们展示了函数的外延性:因为 无论应用上什么参数都是相同的,因此这两个函数也是等价的。

当一个项没法继续使用 -规约,我们就称这个项是 -范式。

当一个项没法使用上述任意一条规则,且被完全应用(也就是每个抽象都有一个对应的应用)我们就称这个项是 -既约的, 简称既约的 (normalized)。

这时我们就会发现无类型 演算的第一个毒点:不是所有的项都能化成 范式,或者说 演算并不是停机的。比如我们考虑以下的项:

我们发现无论如何这个函数都没法被完全规约,它最后总会回到最开始的形式。

邱奇编码

邱奇编码使得 演算具有了更多实用意义。通过邱奇编码,我们能将很多东西,比如自然数、布尔值、有序对等等,映射到一个 中的项。

如邱奇数能让我们用 演算编码自然数。邱奇编码将自然数 ,表示为任意函数 映射到它自身的 重函数复合的一个函数,换言之 是一个接受一个函数 和一个参数 的函数,返回的是把 应用到 次的结果。直观理解一下:

类似地我们能定义加法:,这是我们由定义可以得来的。

类似地我们还可以做很多有趣的东西。但是对类型论这不太重要。有时间可能会回来补。

重要的是,我们不得不开始考虑 或者类似东西的意义——它的确是一个合法的 项,我们也可以用规则去化简它,但是它和意义很混乱—— 加上一个函数是什么?我们没法解释。这就是无类型 演算的另一个弊端:虽然我们能表示不同“种类”的东西,但是我们没有手段来确保函数或是其它东西按照我们预想的方式使用它——毕竟不论什么含义最终都是 项,无论多么胡闹的用法都是合法的。这就需要我们用类型来规范函数的行为。

简单类型 演算

类型论和一个类型论

正如集合论根据承认的公理不同有许多分支,类型论也有许多不同的“版本”,如上面提到的无类型 演算,和接下来要讲的简单 演算,这些都可以叫做是“一个类型论”,而“类型论”是研究“这些类型论”的学科。

定义类型

我们不妨用 表示所有简单类型的集合,用 来表示 “ 是一个类型”。对于简单类型 演算,类型是从一个基本集合开始递归定义出来的。首先我们先选定一个基本类型的集合 ,这些都是基本类型(Type Varibles):

在此之上,我们可以递归定义 Arrow Types(我放弃翻译了)

或者抽象一点的形式,我们可以写成

语境

类型论中的语境(context)是用来记录在当前,有哪些项存在,它们又拥有哪些类型的,类似列表状物。

语境的定义也是递归的——这和一些函数式语言定义列表的方式相似。首先不包含任何信息的“空列表”是一个语境,我们称其为“空语境”:

在此之上,我们可以追加一个新的陈述,构成一个新的语境:

我们用记号 来代表 是一个合法的,具有 类型的项,这被称为是一个陈述(statement)。而对一个语境 中,我们用 来表示“在 这个语境下, 是一个合法的项,且具有 类型”,这被称为是一个 判断(judgement)。

在简单类型 演算中,每个项(Term)都必须有其对应的类型,我们在讨论一个项时不能脱离其类型和所在的语境,这使得我们对项的定义略微复杂一些,其包含四个规则。

首先我们指定一个常量集合 ,并给定一个映射 ,为每个常量指定一个类型(映射到 应当也没问题,但我们希望这些常量基础一些),这些是我们指定的基础的项:

同时我们还希望能从语境中提取信息得到一个合法的项:

另外我们还希望引入 演算来构建项,这时的 演算要时刻记得考虑类型:

转换

在简单类型 演算中我们仍然可以使用 转换。这里我们略去。

规约

同样我们可以在简单类型 演算中对项进行规约。这些规则在学习了无类型 演算之后应该能比较自然地猜出来:

加入了类型之后规约有了一些更好的性质,我们来简单讨论一下。

首先我们定义符号 代表 经过一步 规约得到了 代表 经过多步 规约得到了