PFPL概念归纳

总结形式化语言的相关概念。源自于教材Practical Foundations for Programming Languages。这个总结作为辅助阅读资料,无法代替教材本身。


Chapter1: Abstract Syntax

抽象语法。用树状结构表达。书中的内容不关注具体的语法,仅仅关注语法片段(句法)对应的树,以及树中的标识符(类似于变量)的绑定关系(类似于变量的赋值)。这本书主要关注语法的结构化信息,对于语法最后是如何用字符串表达的并不关心。

abstract syntax tree。 抽象语法树,经常用 a a a表示。叶子被称作variables,非叶节点(内部节点)被称作operators。

sort。语法树的类型。不同类型的语法树对应不同形式的语法。比如SQL语句和一般的C++编程是用的不同的语法。经常用 s s s表示。经常用 S S S表示sort的集合。

variable。未指定的或者通用的语法片段。一个未知的占位符,其具体的含义与其替代者有关。经常用 x x x表示。用 χ \chi χ表示集合。用 χ s \chi_s χs表示对应类型的所有变量的集合。我们可以使用 A [ χ ] = { A [ χ ] s ∈ S } A[\chi]=\{A[\chi]_{s \in S}\} A[χ]={A[χ]sS}来代表类型为 s s s的语法树,这个语法树中的变量是类型 s s s的、以及所有operator在连接不同子树之后也是类型 s s s的。当然,也可以使用 A [ χ 1 , χ 2 ] A[\chi_{1}, \chi_{2}] A[χ1,χ2]来并联多个集合。

operator。语法树的内部(非叶)节点。通常使用 o o o来表示。 O O O用来表示operator的集合。其子节点被称作argument(参数)。其内部包含一个叫做arity的概念来表达operator及其参数的类型。用 o ( a 1 ; . . . ; a n ) o(a_1;...;a_n) o(a1;...;an)代表一个包含了语法树 a 1 a_1 a1 a n a_n an作为子节点的operator。

arity。元数。一般用变量 α \alpha α表示。其完整表示为 ( s 1 , . . . , s n ) s (s_1,...,s_n)s (s1,...,sn)s,其代表对应的operator为类型 s s s,带有 n n n个参数(子节点),每个参数的类型为 s 1 s_1 s1 s n s_n sn。通过将arity考虑在内。我们可以使用 O α O_\alpha Oα来表示相同arity的operator的集合。

structural induction。结构归纳。 如果要证明语法树 a a a满足某一个属性 P P P,即 P ( a ) P(a) P(a)。我们只需要证明1) a a a中所有的变量 x x x满足属性 P P P;2)每一个operator在连接了其子树(参数)之后所形成的新 抽象语法树也满足属性 P P P。在全局不明朗,变量替代关系复杂的树状结构中,结构归纳只证明小的单元,然后推广至全局的方法来证明语法树的性质。

substitution。替代。用一个语法片段去代替语法树中的一个变量。 [ b / x ] a [b/x]a [b/x]a代表用语法树b替代语法树 a a a中所有命名为 x x x的变量。

abstrast binding tree。抽象绑定树。解决变量的作用域问题。在语法片段中,如果变量 x x x特指是语法树 a a a中的 x x x,需要将变量写成 x . a x.a x.a。这是相对于abstract syntax tree唯一的区别。这是x被称作绑定变量(减occur free)。抽象绑定树可以用于表达函数式编程、匿名函数和lambda文法。在文法中,函数的声明和函数调用可能出现在一行代码中。这时绑定变量就更像是匿名函数的形参和局部变量,这些绑定变量是不会在匿名函数外面被替换和赋值的。

abstractor。抽象绑定树相比抽象树,加入的新语法。即abstract binding tree中的operator中的argument的新名字。使用 x 1 , . . . , x n . a x_1,...,x_n.a x1,...,xn.a表达绑定在语法树 a a a中的变量 x 1 x_1 x1 x n x_n xn,变量可以进一步写成向量 x ⃗ . a \vec{x}.a x .a来简介表达。从此之后,operator的子节点变成了abstractor。abstractor感觉像匿名函数的声明。

generalized arity。广义的元数。扩大了arity的原始定义。表示为 ( v 1 , . . . , v n ) s (v_1,...,v_n)s (v1,...,vn)s。其中 s s s为operator的类型, v v v是valence,直译是化合价的意思,代表一个语法抽象树(原子)和其绑定的变量(化学键)。 v v v可以进一步表达为 s 1 , . . . s n . s s_1,...s_n.s s1,...sn.s s ⃗ . s \vec{s}.s s .s,其中s是argument(连在operator下面的一个小语法树)的类型, s 1 s_1 s1 s n s_n sn是每一个绑定的变量的类型。

fresh renaming。重命名操作。在抽象绑定树中存在嵌套关系,即一个抽象绑定树是另外一个抽象绑定树的子树。如果这个时候两个层次的抽象绑定树的绑定变量的名字是一样的,会造成歧义,故需要引入重命名,让其中一个语法树的绑定变量的名字错开。

α \alpha α-equivalent α \alpha α等价。如果两个abt可以通过改变变量名来使得二者完全相同,那么这两个abt被称作 α \alpha α等价。

occur free。一个变量如果在一个abstractor中是occur free的,代表这一变量是可以被替换(substitution)的。但是如果一个变量是被绑定的,那它就是不能被替换的。这里涉及到自由变量和绑定变量的区别维基百科—自由变量与绑定变量。简单来说,绑定变量是一种形式上的变量,可以类比于编程语言中函数声明中的形参和函数内的局部变量。这种变量本质上是被固定在了一个作用域中,用以介绍一段逻辑,外部的赋值不会影响到函数内部。自由变量是真正的、实际的变量,可以被替换(在编程语言中称为赋值),可以理解为编程语言中的全局变量。

symbolic parameter(symbol)。符号参数。抽象语法并不在任何时候都包含固定的operator。有时,一个operator是否可用与当前语法的上下文有关。我们使用symbolic parameter,或者symbol来表示operator的集合的索引,只有symbolic parameter是活跃的,对应的那些operator才是可用的,用 u u u表示,用 U U U代表symbol的集合。 o [ u ] o[u] o[u]表示与symbol u u u对应的operator o o o。语法绑定树的定义可以进一步扩展,用 B [ U ; χ ] B[U;\chi] B[U;χ]代表语法绑定树的集合,包含了符号集合 U U U和变量集合 χ \chi χ。与variable(变量)一样,symbol也支持绑定到一定的语法树中,比如abstractor u . a u.a u.a。symbol和variable在重命名上是完全一致的,只要不产生新的冲突,但是除此之外,symbol就有所不同,symbol不是一个占位符,不能被替换。


Chapter 2: Inductive Definitions

归纳定义。一种编程语言的基本工具。用递归的方式来做出定义。structural induction是一种特殊的归纳定义。

judgment。判断,也被称作assertion,断言。judgement是一种对于语法树性质和多个语法树关系的描述。

judgement form。判断形式,也称作谓词predicate。判断中的性质与关系。用 J J J去表示。谓词是归纳定义的定义对象。

instance of judgement form。谓词的实例,也就是谓词加上主语subjects。主语表达了性质与关系所作用的对象。使用 a   J a\ J a J或者 J   a J\ a J a代表语法(绑定)树满足谓词 J J J。有时候如果主语暂时缺席,那就变成 −   J -\ J  J或者 J   − J\ - J 用一个占位符来代替。在有些语境下主语并不重要,这个时候可以直接使用 J J J来表达整个断言。

rule。规则。写成 J 1 , . . . , J k J \frac{J_1,...,J_k}{J} JJ1,...,Jk的形式,上面的断言是被称作rule的前提premise,下面的被称作rule的结论conclusion。读作前提对于结果是充分的sufficient。如果一个rule没有前提,那么其就被称作公理axiom。对于某一个谓词inductive definitions由一系列的rule构成。rule的集合一般写做 R R R

iff。当且仅当。iff会连接两个断言,代表二者之间是相互推导,充分必要的关系。

rule scheme。规则族。rule中的judgement的主语有时是一个变量,因为变量可以无限地被替换。带有变量的rule本质上是一堆rule的集合,称为规则族,对于主语的不同的、具体的替换构成规则族的一个实例,也就是规则。

derivation。推导。证明一个judgement有效的过程。推导过程从公理开始,通过连接不同rule的前提和结论,最终在推导过程的尾部案得到某一个judgement。一般用符号 ∇ \nabla 来表示。

closed under。闭包。一个在不同领域有不同具体含义的概念。如果一个judgement可以通过一系列给定rule来推导得出,那么我们就可以说这个judgement闭包于这些rule。closed under说明了rule对于judgement的推导是充分的,即通过给定的rule可以找到一种方式来证明judgement的有效性。可以用拓扑学和集合论和角度来解释闭包这个概念。通过组合rule可以得到很多的推理路径(有向图),这些路径中节点是judgement,边是rule(边的起点是premise,终点是conclusion)。那么通过组合各种各样的rule可以得到命题的集合,如果一个judgement包含在所有rule的合理组合而形成的图中,那么这个judgement就是这些rule的一个闭包。

strongest judgement。强断言。是一种相比闭包更为严格的条件。如果一个judgement闭包与给定的rule,并且能且只能由给定的rule推导得出,那么就可以将其称为闭包于给定rule的strongest judgement。这些rule对于strongest judgement的推导是必要的。

rule induction。规则归纳。归纳定义(inductive definition)的一种方式。规则归纳出现在我们要推理的judgement(所定义的性质)既是一推rule要推理的目标,又存在于这些rule的前提之中。所谓”我推理我自己“。数学归纳法就是一个规则归纳,即通常中一个基础的对象对应的断言出发,然后通过加入一个假设(归纳假设),扩展到整个值域。rule induction必须保证judgement是strongest judgment。PFPL在为什么要strongest judgment,没说明原因。我猜测只有strongest judgment才能保证对于一个推理的路径是唯一的,从而使得归纳过程可以无限递归下去。或者如果在前提中包含了目标judgement的rule集合不是唯一的推理路径,那么可能使用普通的、不递归的其他方式也可以推理出目标judgement,rule induction就不是必须的。


Chapter 3: Hypothetical and General Judgements

这一章节包含了两种进阶的断言。与Chapter 2介绍的judgement不同(这一章将这类断言称作basic judgement),Chapter 3中的断言更像是“断言的断言”,与之前的以语法树为对象的断言不同,这一章的断言的对象也是断言。这一章的两种断言,一个是hypothetical judgement,研究的是假设与可推理性,还有可接受性。另外一种断言是general judgment,研究的是断言的变量(见variable的概念)的不同重命名和替换以及断言的符号参数(见symbolic parameter的概念)的重命名对于断言有效性的影响。此外,这一章还给出了两种进阶的断言对应的rule和rule induction(归纳定义)。

derivability judgement。可推导性断言,假设性断言的一种。这类断言可以表达为 J 1 , . . . , J k ⊢ R K J_1,...,J_k\vdash_RK J1,...,JkRK。其中 J J J K K K都代表断言, J J J可以进一步称为假设(hypothesis),可以用符号 Γ \Gamma Γ △ \triangle 代表所有假设的集合。 R R R代表规则的集合。 ⊢ \vdash 是可推导的意思,可以不带假设,单独使用 ⊢ R Γ \vdash_R\Gamma RΓ表示,代表 R R R中的规则可以推导出 Γ \Gamma Γ中所有的judgement。这个断言可以表达为本质相同的四种意思:

  1. 假设所有的 J J J都成立,进一步利用 R R R中的规则可以推导出 K K K
  2. J 1 , . . . , J k J_1,...,J_k J1,...,Jk全部视为公理 J 1 , . . . , J k \frac{}{J_1},...,\frac{}{J_k} J1,...,Jk,那么可以依据 R R R中的rule和这些公理,即 R ∪ J 1 , . . . , J k R\cup\frac{}{J_1},...,\frac{}{J_k} RJ1,...,Jk,找到一条使 K K K成立的推导( ⊢ R ∪ J 1 , . . . , J k K \vdash_{R\cup\frac{}{J_1},...,\frac{}{J_k}}K RJ1,...,JkK)。这一解释可以帮助我们理解derivability judgement的一系列性质。
  3. 规则 J 1 , . . . , J k K \frac{J_1,...,J_k}{K} KJ1,...,Jk可以推导自 R R R中的规则。

stability of derivability judgement。可推导性断言的稳定性。扩展可推导性断言中的规则集合不会影响可推导性断言的有效性。如果 Γ ⊢ R J \Gamma\vdash_RJ ΓRJ,那么 Γ ⊢ R ∪ R ′ J \Gamma\vdash_{R\cup R'}J ΓRRJ

reflexivity of derivability judgement。可推导性断言的反射性。每个(假设中的)断言都是自身的结论,这个很好理解。即 Γ , J ⊢ R J \Gamma,J\vdash_RJ Γ,JRJ

weakening of derivability judgement。可推导性断言的弱化。增加的额外假设,不影响可推导性。即若 Γ ⊢ R J \Gamma\vdash_RJ ΓRJ成立, Γ , K ⊢ R J \Gamma,K\vdash_RJ Γ,KRJ也成立。 K K K为额外增加的假设。

transitivity of derivability judgement。可推导性断言的传递性。如果假设中的一部分断言可以从另外的假设和规则集合 R R R中推导出来,那么这部分断言是可以忽略的。即如果 Γ , K ⊢ R J \Gamma,K\vdash_RJ Γ,KRJ并且 Γ ⊢ R K \Gamma\vdash_RK ΓRK,那么 Γ ⊢ R J \Gamma\vdash_RJ ΓRJ K K K能被剩下的部分假设 Γ \Gamma Γ以及规则 R R R推导出来,所以 K K K可以被忽略。

admissibility judgement。可接纳性断言,另一种假设性断言。如果规则可以推导出某些judgement,那么也一定能推导出另外的judgement。表达为 Γ ⊨ R J \Gamma\models_RJ ΓRJ。有本质相同的两种意思:

  1. 假设(如果) ⊢ R Γ \vdash_R\Gamma RΓ成立,那么 ⊢ R J \vdash_RJ RJ也成立。
  2. Γ \Gamma Γ中的断言为 J 1 , . . . , J n J_1,...,J_n J1,...,Jn。那么 J 1 , . . . , J n J \frac{J_1,...,J_n}{J} JJ1,...,Jn相对于 R R R是可接受(admissible)的。如果可以推出前期,那么结论也一定是成立的。

如果假设 Γ \Gamma Γ中的断言实际上没法被 R R R中的规则推导出来,那么这个admissibility judgement只能说是“虚真的”(vacuously true)。admissibility judgement能够成立通常是因为 R R R对于断言假设的推理路径可以“经过”可接纳性断言的结论。admissibility是一种比derivability更宽松的断言,有时候 Γ ⊢ R J \Gamma\vdash_RJ ΓRJ不成立,但是 Γ ⊨ R J \Gamma\models_RJ ΓRJ是成立的。

no stability of admissibility judgement。可接受性断言的不稳定性。扩展可接受断言的rule集合 R R R并不能保证可接受性断言的继续成立。因为新加入的规则会改变 R R R对于断言假设推理路径,从而反而使得可接受性断言不成立。但是如果扩展的rule相对于 R R R是可接受(admissible)的,那么这个rule的扩展就不影响admissibility judgement的有效性。因为此时R对于rule前提的推导是经过rule的结论的。rule的扩展相当于在R原来的推理路径上加上“回头路”,不影响原本推理路径所经过的断言,也就不影响可接受性断言本身。

reflexivity of admissibility judgement。可接受性断言的反射性。如果假设相对于 R R R是可推导的,那么显而易见,与假设相同的结论也是可推导的。即 J ⊨ R J J\models_RJ JRJ

weakening of admissibility judgement。可接受性断言的弱化。增加断言的假设不影响断言是否成立。即如果 Γ ⊨ R J \Gamma\models_RJ ΓRJ那么 Γ , K ⊨ R J \Gamma,K\models_RJ Γ,KRJ。新增加的假设不影响对于原来假设的推理路径,也就不影响推理路径经过断言 J J J

transitivity of admissibility judgement。可接受性断言的传递性。如果一部分假设相对于剩余的假设和rule集合是可接受的,那么这部分假设可以不需要。即如果 Γ , K ⊨ R J \Gamma,K\models_RJ Γ,KRJ并且 Γ ⊨ R K \Gamma\models_RK ΓRK,那么 Γ ⊨ R J \Gamma\models_RJ ΓRJ。如果 K K K已经在 R R R对于 Γ \Gamma Γ的推理路径中经过了,那就不需要再做出假设了。

formal derivability judgement。形式可推导断言。代表两组断言之间存在可以推导的关系,但是不关心具体是怎么推导的。即 Γ ⊢ J \Gamma\vdash J ΓJ,代表存在某种方式使得 Γ \Gamma Γ中的judgement可以推导出 J J J中的judgement。这一概念为derivability judgement多了一种解释: Γ ⊢ R J \Gamma\vdash_RJ ΓRJ代表了形式可推导断言 Γ ⊢ J \Gamma\vdash J ΓJ可以推导自规则集合 R R R

hypothetical rule。假设规则。在premise和conclusion中包含formal derivability judgement的规则:
Γ Γ 1 ⊢ J 1   . . .   Γ Γ n ⊢ J n Γ ⊢ J \frac{\Gamma\Gamma_1\vdash J_1 \ ... \ \Gamma\Gamma_n\vdash J_n}{\Gamma\vdash J} ΓJΓΓ1J1 ... ΓΓnJn
其中 Γ \Gamma Γ被称作全局假设(global hypothesis), Γ 1 , . . . , Γ n \Gamma_1,...,\Gamma_n Γ1,...,Γn,称作对应前提的局部假设(local hypothesis)。与basic judgement的推导一样,formal derivability judgement的证明会依赖假设规则集合 R R R来做出推理。因为这里是假设断言的范畴,所以形式可推导断言的证明除了依赖于 R R R还会依赖于derivability judgement的性质(见derivability judgement部分的介绍)。此外,一般来说,可以规定在 R R R中的所有rule的全局假设是统一的。故假设规则可以简化为更局部的形式:
Γ 1 ⊢ J 1   . . .   Γ n ⊢ J n J \frac{\Gamma_1\vdash J_1 \ ... \ \Gamma_n\vdash J_n}{J} JΓ1J1 ... ΓnJn
hypothetical rule induction。假设规则归纳,由一系列rule对于形式可推导断言某一性质的定义 P ( Γ ⊢ J ) P(\Gamma\vdash J) P(ΓJ)(猜测可能是形式可推导断言中的语法树的性质)。与之前rule induction所表达的归纳定义是一个意思。都是为了某一性质在rule前提与假设之间的传递。在假设规则中,具体说,如果 P ( Γ Γ 1 ⊢ J 1 ) , . . . , P ( Γ Γ n ⊢ J n ) P(\Gamma\Gamma_1\vdash J_1),...,P(\Gamma\Gamma_n\vdash J_n) P(ΓΓ1J1),...,P(ΓΓnJn)都被满足,那么 P ( Γ ⊢ J ) P(\Gamma\vdash J) P(ΓJ)也能被满足。在此基础上,就可以进行归纳定义。

uniformity of rules。rule的一致性。集合 R R R中的rule如果是满足一致性的,那么其中任意一个rule中的变量和symbol被重命名、被替换所产生的rule也被包含在 R R R中。

general derivability judgement。一般性可推导断言。关注断言中的语法树的variable的renaming和substitution以及symbolic parameter的renaming对于可推导性的影响(详见Chapter 1)。用符号 Γ ⊢ R U ; χ J \Gamma\vdash_{R}^{U;\chi}J ΓRU;χJ来代表 Γ \Gamma Γ可以通过规则集 R R R推导出 J J J。在这一可推导性断言中的所有variable包含集合 χ \chi χ中,所有的symbol包含在集合 U U U中。对于一个一般性可推导断言,如果有可推导性断言 Γ ⊢ R χ   Y J \Gamma\vdash_{R}^{\chi\ Y}J ΓRχ YJ χ \chi χ Y Y Y都是变量的集合,其中 Y Y Y中都是可以随意命名和替换的变量,那么一般性可推导断言可以将“自由”的变量放到外面去。 Y ∣ Γ ⊢ R χ J Y|\Gamma\vdash_R^\chi J YΓRχJ,代表Y中的变量无论怎么赋值和重命名,都不改变可推导性。此外这里要求 R R R中的规则是满足uniformity的。当然,symbolic parameter的重命名也是一样的。可以用双杠放在更前面来表示: V ∣ ∣ Y ∣ Γ ⊢ R U , χ J V||Y|\Gamma\vdash_R^{U,\chi}J VYΓRU,χJ V V V是可以随意命名的symbol。

formal generic judgement、generic rule、generic inductive definition。与formal derivability judgement、hypothetical rule、hypothetical rule induction的定义类似。


Chapter 4: Statics

(编程语言)静力学。用以在程序编写完之后、运行之前检查程序的语法。主要以表达式的类型检查为主。

abstract syntax。抽象语法。本质上是对于语法树的描述,包含了一系列的operator及其arity。BNF范式是表达语法的常用方法。从类型检查的角度来说,一个语法表中包含两种sort的语法,一种是表达式,即expression;另一种是表达式的类型,即type。注意sort与type两个概念的区别。sort是abt的种类(例如表达式是一种abt,是一种语法类型),type是表达式的类型(有类似于编程语言中的数据类型)。

typing judgment。类型系统中有关类型的断言。 表达为一般性假设断言,声明一个表达式的类型。 χ ∣ Γ ⊢ e : τ \chi|\Gamma\vdash e:\tau χΓe:τ(” : : :“用来表达类型),代表表达式 e e e的类型(type)为 τ \tau τ χ \chi χ代表上下文中的变量集合,这些变量是可以被随意替换和重命名的。在这一语境中,假设 Γ \Gamma Γ被称为类型上下文(type context),代表表达式上下文的中的( χ \chi χ中的)变量类型(有时表达式 e e e的类型由其上下文中其他变量的类型决定)。 x ∈ d o m ( Γ ) x\in dom(\Gamma) xdom(Γ)代表变量 x x x没有出现在类型上下文中(fresh)。

typing rule。类型系统中的规则。用来定义一个表达式的type的推理,前提是一般是其子表达式的type,结论一般是这些子表达式(作为abt中的变量)构建的更大表达式的type。也有一些rule是没有前提的axiom,强制规定某种表达式的type,通常是针对的非常简单的表达式,比如编程语言中变量(这里指的不是abt的变量)和常量。typing rule是强烈语法导向的,一般来一条语法规则对应一个typing rule。

unicity of typing。类型的独特性。对于每一对上下文 Γ \Gamma Γ和表达式 e e e,最多只能有一个类型 τ \tau τ使得 Γ ⊢ e : τ \Gamma\vdash e:\tau Γe:τ

inversion for typing。类型的倒置。根据表达式,可以反推出其表达式的类型以及表达式中变量(语法的、abt的变量)的类型。

weakening of statics。静力学的弱化。在假设中增加不存在于typing context( Γ \Gamma Γ)的 x : τ x:\tau x:τ,不影响这一typing context中表达式的类型。

substitution of statics。静力学的替换原则。表达式本质上是一个abt,将abt中的变量替换为与这个变量type相同的子abt,不影响外层的表达式的类型。替换原则类似于软件中调用过程,我们在调用一个函数时本质上调用的是函数的签名,但是最终这个签名会被函数的实现替换。abt、expression的本质就是一个代码段。

decomposition of statics。静力学中的分解。替换的逆过程。表达式中的子表达式可以分离出来,并且在对应位置放上变量。可以将一个表达式分解为等效的两个小表达式。

introduction and elimination。语法构建的两种形式:介绍和消除。introduction直接决定了一个值的type(什么是什么),elimination决定了怎么用同一个类型的一系列值在计算之后去形成另一个类型(让复杂的、带有变量的表达式最终简化为自身的introduction form)。

closed expression。封闭的表达式。当表达式中的所有的variable所代表的子表达式都计算成值(value)了,当前表达式已经可以被直接计算为值了,那么这一表达式称为封闭表达式。


Chapter 5: Dynamics

代码动力学。主要是研究代码怎么被执行的。主要包含了三种动力学:structural dynamics(表达式在一步步执行中的变化),contextual dynamics(对于一个多层嵌套的复杂表达式来说,表达式不同部分的执行顺序),equational dynamics(表达式之间的等效关系)。在这一章中,编程语言的表达式(expression)基本等同于计算机程序(program)或者指令(instruction)。

transition system。变迁系统。类似于状态机。变迁系统中包含一系列state(状态)。包含initial(起始状态)和final(终结状态)作为一开始的状态和结束的状态。以及它们之间变迁的方式。如果每一个状态最多只有一个后继状态,那么就说这一变迁系统是确定的(deterministic)。

transition judgement。变迁断言。用 s ⟼ s ′ s\longmapsto s' ss代表state s s s和state s ′ s' s之间的转换。另外,如果强调两个状态之间包含多步的变迁。 s ⟼ ∗ s ′ s\longmapsto^* s' ss代表两个状态的变迁是0步或者多步的。当然也可以通过将星号变成一个数字来表达两个状态的变迁步骤的数量,比如 s ⟼ 0 s s\longmapsto^0 s s0s或者 s ⟼ k s s\longmapsto^k s sks

transition sequence。变迁序列。如果state s 0 , . . . , s n s_0,...,s_n s0,...,sn依次变迁, s 0 s_0 s0是起始状态,那么这个序列叫做变迁序列。如果 s n s_n sn之后没有状态了, 这一序列被称作最大的(maximal)。如果 s n s_n sn是终结状态,那么这个序列是完整的(complete)。

structural dynamics。结构动力学。将语言的表达式视为state,那么就可以针对一个语言建立一个表达式的变迁系统,表达了表达式的变化关系。比如 p l u s ( n u m [ n 1 ] ; n u m [ n 2 ] ) ⟼ n u m [ n ] plus(num[n_1];num[n_2])\longmapsto num[n] plus(num[n1];num[n2])num[n]。这些变化都有前提,都有对应的rule。rule分为两种, n 1 + n 2 = n p l u s ( n u m [ n 1 ] ; n u m [ n 2 ] ) ⟼ n u m [ n ] \frac{n_1+n_2=n}{plus(num[n_1];num[n_2])\longmapsto num[n]} plus(num[n1];num[n2])num[n]n1+n2=n叫做指令变迁(instruction transition),代表一个expression真正执行产生的变迁,反应了其原始语义。还有一种叫搜索变迁,表达了一个表达式内部的指令(子表达式)的计算顺序(规定计算过程),比如 e 1   v a l      e 2 ⟼ e 2 ′ p l u s ( e 1 ; e 2 ) ⟼ p l u s ( e 1 ; e 2 ′ ) \frac{e_1 \ val \ \ \ \ e_2\longmapsto e_2'}{plus(e_1;e_2)\longmapsto plus(e_1;e_2')} plus(e1;e2)plus(e1;e2)e1 val    e2e2代表operator plus的第一个参数先变迁(计算)到一个具体的值之后才能变迁(计算)第二个参数所对应的表达式。

by-value and by-name interpretation。按值解释和按名字解释。值,value,被认为是一个表达式变迁过程的final state。从introduction and elimination的角度来说,introduction form就是一个表达式已经不可再算的最终状态,就是value,elimination form就是用rule来规定表达式的内部子表达式的计算,直到子表达式都变成了introduction form。按值解释,是在一个子表达式的实例带入母表达式的对应变量之前先计算出值。按名字解释,子表达式在带入之前不进行任何计算而直接带入。二者的存在都是为了在执行的过程中省计算量,当一个表达式在程序中(其他表达式中)出现多次时,by-value可以将多次对于一个子表达式的计算合并成一次计算,但是对于一个注定不会被算到的子表达式来说,by-value的策略就会产生额外的、不需要的计算,这种情况时by-name的方式是更好的。

contextual dynamics。上下文动力学。结构动力学的变体,为了进一步强调指令执行的顺序。上下文动力学包含了结构动力学也包含的指令变迁,只是符号变成了单纯的箭头 p l u s ( n u m [ n 1 ] ; n u m [ n 2 ] ) ⟶ n u m [ n ] plus(num[n_1];num[n_2])\longrightarrow num[n] plus(num[n1];num[n2])num[n]。而结构动力学中的搜索变迁在上下文动力学中变成执行上下文(evaluation context),用 ε \varepsilon ε表示 。执行上下文是一个被挖掉一部分的表达式,是下一个要执行的表达式(指令)的母表达式的其他部分。被挖掉的部分被称作hole,用符号 ∘ \circ 表示。 ∘ \circ 中的表达式就是下一个要执行的指令。使用符号 e ′ = ε { e } e'=\varepsilon\{e\} e=ε{e}代表上下文 ε \varepsilon ε中的孔洞被表达式 e e e填满之后形成了完成表达式 e ′ e' e。那么上下文动力学就能表达为 e 0 ⟶ e 0 ′ ε { e 0 } ⟼ ε { e 0 ′ } \frac{e_0\longrightarrow e_0'}{\varepsilon\{e_0\}\longmapsto \varepsilon\{e_0'\}} ε{e0}ε{e0}e0e0

equational dynamics。等价动力学。与结构或者上下文动力学都不同,等价动力学研究程序之间的等价关系。这一等价关系被称为定义等价性或者计算等价性。等价的概念可以表达为 χ ∣ Γ ⊢ e ≡ e ′ : τ \chi|\Gamma \vdash e\equiv e':\tau χΓee:τ。一般隐含地要求 e e e的类型和 e ′ e' e是一样的。两个表达式等价,说明两个表达式最终可以变迁到相等大小的值上。同时等价也有结构化的性质,自身与自身是等价的(反射性), ≡ \equiv 两侧的内容可以交换(交换性), e ≡ e ′ e \equiv e' ee以及 e ′ ≡ e ′ ′ e' \equiv e'' ee那么 e ′ ≡ e ′ ′ e'\equiv e'' ee(传递性)。


Chapter 6: Type Safety

类型安全。类型安全代表程序在语法上完全正确。Statics和Dynamics都可以保证类型安全,Statics主要在运行前通过type system保证,Dynamics主要通过transition system来检查运行时错误。

type safety。类型安全,类型安全要满足两个条件。第一个称为preservation(类型保存),代表一个变迁断言 e ⟼ e ′ e\longmapsto e' ee前后的两个状态的type必须是一样的,即如果 e : τ e:\tau e:τ,那么 e ′ : τ e':\tau e:τ。第二个条件称为progress,代表如果一个表达式不是值,那么它就应该可以变迁下去。

run-time error。运行时错误。有些错误在静力学阶段难以通过类型系统推断出来,那么在动力学阶段加入名为error的表达式和相关变迁规则来处理就可以,一旦出现错误的前提,那么直接变迁出error来弹出错误即可。而与一般编程语言的异常处理一样,在变迁系统中除了要规定错误的产生的直接rule之外,还需要给出子表示中的错误怎么从外层表达式传递的问题,即当子表达式变迁到error之后,外层表达式也要变迁到error。


Chapter 7: Evaluation Dynamics

计算动力学。有时候为了简化dynamics的表达,我们需要仅仅关注表达式的计算结果,而对于其具体的执行过程乃至类型安全的检查都不在意,那么我们可以使用evaluation dynamics。

evaluation judgement。计算断言。表达为 e ⇓ v e\Downarrow v ev,代表封闭表达式 e e e(见chapter 4)可以计算出值 v v v,用结构动力学可以表达为 e ⟼ ∗ v e\longmapsto^* v ev。此外,一个表达式 e e e的计算结果和其在变迁系统的后继表达式 e ′ e' e的计算结果是一致的,即如果 e ⟼ e ′ e\longmapsto e' ee并且 e ′ ⇓ v e'\Downarrow v ev,那么 e ⇓ v e\Downarrow v ev

rule of evaluation dynamics。计算动力学中的规则。一个语法的计算动力学由一大堆规则构成,规则前提是一个表达式中子表达式的结果以及表达式自身的语义,规则的结论是表达式自身的计算结果。例如, e 1 ⇓ n u m [ n 1 ]    e 2 ⇓ n u m [ n 2 ]    n 1 + n 2 = n p l u s ( e 1 ; e 2 ) ⇓ n u m [ n ] \frac{e_1\Downarrow num[n_1]\ \ e_2\Downarrow num[n_2]\ \ n_1+n_2=n}{plus(e_1;e_2)\Downarrow num[n]} plus(e1;e2)num[n]e1num[n1]  e2num[n2]  n1+n2=n。与之前的动力学不同,计算动力学不是语法导向的,不是每一个语法表达式都对应一个动力学规则。

goes wrong。(一个表达式)发生错误。结构动力学通过声明什么样的语法是合法的,来检查错误,不合法的程序会在statics和dynamics过程中违背type safety的preservation和progress的范畴,在变迁过程中被卡住。与结构动力学相反,计算动力学省略了中间过程,所以只能显示地声明什么样的表达式是错误的。所以计算动力学难以进行类型检查,因为在表达式的无穷嵌套和组合中,正确的情况是少的,错误的情况是多的,所以穷尽所有的错误是不现实的。但是依旧有一种断言来定义一个表达式的错误: e ? ? e?? e??

cost dynamics。开销动力学。结构动力学天然地表达了时间复杂度,通过看两个表达式之间变迁的步骤。但是evaluation dynamics因为省略了结构动力学中的中间步骤,所以对于开销的表达就需要额外的定义,通过扩展计算断言为 e ⇓ k v e \Downarrow^k v ekv代表表达式 e e e需要 k k k步来变迁到值 v v v,等效于 e ⟼ k v e\longmapsto^k v ekv。开销动力学包含了一系列由扩展过的evaluation judgement构成的rule,比如 e 1 ⇓ k 1 n u m [ n 1 ]    e 2 ⇓ k 2 n u m [ n 2 ] p l u s ( e 1 ; e 2 ) ⇓ k 1 + k 2 + 1 n u m [ n ] \frac{e_1\Downarrow^{k_1} num[n_1]\ \ e_2\Downarrow^{k_2} num[n_2]}{plus(e_1;e_2)\Downarrow^{k_1+k_2+1} num[n]} plus(e1;e2)k1+k2+1num[n]e1k1num[n1]  e2k2num[n2]


Chapter 8: Function Definitions and Values

函数定义和值。函数表达了对于一个变量的操作。一般来说,一个表达式可能包含多个变量,这些变量中有一个是可变的,剩下的部分是这一变量的上下文,也称作这一变量的函数。函数分为定义和调用两个过程。定义(definition)本质上是将一个变量绑定到一个abt中,并且这一变量本质上就是函数的参数。函数的应用(application)本质上是用一个表达式来替换函数的参数,最终形成一个没有绑定变量的完整表达式的过程。函数的输入是一个表达式(函数的参数),输出是另一个表达式。函数的参数是输出表达式的一个绑定变量,而输入的表达式会替换这个绑定变量。

first-order function。一阶函数。如果一个函数不能作为一个编程语言的变量、不能作为另一个函数的参数和返回值。那么这个函数就是一阶函数。一阶函数调用,表达为 a p p l y { f } ( e ) apply\{f\}(e) apply{f}(e) f f f是函数名, e e e是函数的参数。也可以表达为“将函数名 f f f绑定在参数 e e e上”。一阶函数的定义,表达为 f u n { τ 1 ; τ 2 } ( x 1 . e 2 ; f . e ) fun\{\tau_1;\tau_2\}(x_1.e_2;f.e) fun{τ1;τ2}(x1.e2;f.e)。其中 e 2 e_2 e2是一个类型为 τ 2 \tau_2 τ2表达式,定义了函数的输出(按照编程语言的语境,定义了函数内容),称为range。其中 x 1 x_1 x1是一个类型为 τ 1 \tau_1 τ1,为函数的参数,是 e 2 e_2 e2的一个绑定变量,称为domain。在函数的定义中, e e e是一个表达式,是函数声明的外层表达式,即函数声明会替换到 e e e中。 e e e通常会是函数调用的表达式。

function type of first-order function。一阶函数函数类型。在一般的语法中,一阶函数和一般的表达式是区分开来的。所以除了表达式的类型,还有函数的类型。表达为 f ( τ 1 ) : τ 2 f(\tau_1):\tau_2 f(τ1):τ2,也被称作“函数头”。

statics of first-order function。一阶函数的静力学,用以函数的类型检查。一个是函数声明和调用的类型检查:
Γ , x 1 : τ 1 ⊢ e 2 : τ 2      Γ , f ( τ 1 ) : τ 2 ⊢ e : τ Γ ⊢ f u n { τ 1 ; τ 2 } ( x 1 . e 2 ; f . e ) : τ \frac{\Gamma,x_1:\tau_1\vdash e_2:\tau_2\ \ \ \ \Gamma,f(\tau_1):\tau_2\vdash e:\tau}{\Gamma\vdash fun\{\tau_1;\tau_2\}(x_1.e_2;f.e):\tau} Γfun{τ1;τ2}(x1.e2;f.e):τΓ,x1:τ1e2:τ2    Γ,f(τ1):τ2e:τ

Γ ⊢ f ( τ 1 ) : τ 2      Γ ⊢ e 1 : τ 1 Γ ⊢ a p p l y { f } ( e 1 ) : τ 2 \frac{\Gamma\vdash f(\tau_1):\tau_2\ \ \ \ \Gamma\vdash e_1:\tau_1}{\Gamma\vdash apply\{f\}(e_1):\tau_2} Γapply{f}(e1):τ2Γf(τ1):τ2    Γe1:τ1

function substitution。函数替换。与一般变量的替换类似,表达式中的函数名也可以被替换。KaTeX parse error: Undefined control sequence: \textlbrackdbl at position 1: \̲t̲e̲x̲t̲l̲b̲r̲a̲c̲k̲d̲b̲l̲ ̲x_1.e_2/f \text…,其中 f f f是表达式 e e e中的一个函数名称, x 1 . e 2 x_1.e_2 x1.e2是函数定义的表达式(输出)。因此函数定义的动力学可以写成函数替换的形式:
KaTeX parse error: Undefined control sequence: \textlbrackdbl at position 55: ….e)\longmapsto \̲t̲e̲x̲t̲l̲b̲r̲a̲c̲k̲d̲b̲l̲ ̲x_1.e_2/f \text…
higher-order function。高阶函数。不将函数的语法视为特殊的,将函数视为一般的变量,将函数的调用视为一般的表达式。在高阶函数中,一个函数可以作为另外一个函数的参数(domain)或者输出(range),这是与一阶函数最大的不同。

λ \lambda λ-abstraction。函数的一种表达方式。写成 λ { τ 1 } ( x . e ) \lambda\{\tau_1\}(x.e) λ{τ1}(x.e),是一个值。 e e e是函数的定义或者输出, x x x绑定于 e e e是函数的参数。或者表达为 λ ( x : τ 1 ) e \lambda(x:\tau_1)e λ(x:τ1)e。在函数调用的时候,后面加上一个括号,在括号中加入一个type为 τ 1 \tau_1 τ1的表达式来实例化 x x x即可。

function type of higher-order function。高阶函数的函数类型。用函数输入表达式的类型 τ 1 \tau_1 τ1和输出表达式的类型 τ 2 \tau_2 τ2来定义高阶函数的类型,表达为 τ 1 ⟶ τ 2 \tau_1 \longrightarrow \tau_2 τ1τ2

dynamics of higher-order function。高阶函数的动力学。用 a p ( e 1 , e 2 ) ap(e_1,e_2) ap(e1,e2)代表函数的调用 e 1 ( e 2 ) e_1(e_2) e1(e2),这一过程可以变迁为一个对表达式 e 1 e_1 e1中绑定变量的替换过程:
a p ( λ { τ 2 } ( x . e 1 ) ; e 2 ) ⟼ [ e 2 / x ] e 1 \frac{}{ap(\lambda\{\tau_2\}(x.e_1);e_2)\longmapsto [e_2/x]e_1} ap(λ{τ2}(x.e1);e2)[e2/x]e1
static scoping(binding)。静态绑定。变量具有作用域,变量的名字仅仅代表在一个abt内的那个变量,如abt的定义一样。

dynamic scoping。动态绑定。相当于变量没有作用域,所有的自由变量都是编程语言中的全局变量,在实际的运行中,根据执行的情况,某一个变量会被不同的作用域的同名变量改变其赋值,那么一个变量的赋值由其最后一次被赋值决定。Dynamic scoping in Lua举了一个例子。dynamic scoping只在高阶函数中存在,高阶函数可以通过互为输入输出嵌套在一起,才有内部的变量重名问题。动态绑定没法保证类型安全,在当代的编程语言中已经不存在了。


Chapter 9: System T of Higher-Order Recursion

System T,关注一个程序是不是可以结束的。其核心语法为递归。System T中的递归强制了递归的次数。System T只关注自然数和函数,任何可以被System T的语义表达的程序是可以保证“一定可以结束的程序”。

recursor。递归器。每一轮递归都是拿上一轮递归的结果、当前的递归次数作为输入,得出这一轮递归的新结果用以下一轮递归。表达为 r e c { τ } ( e ; e 0 ; x . y . e 1 ) rec\{\tau\}(e;e_0;x.y.e_1) rec{τ}(e;e0;x.y.e1)。其中, e 0 e_0 e0是递归计算的初值, e e e是要递归的总次数, e 1 e_1 e1是每一轮递归中要执行的表达式。 e 1 e_1 e1中有两个绑定变量, x x x代表当前已经递归次数,当 x x x不断自增、到达 e e e后递归过程会停止。 y y y是每一轮递归的结果和下一轮递归的输入,一开始从 e 0 e_0 e0开始,最后作为整个递归过程的输出。

statics of recursion。递归的静力学。递归相关的类型规则有很多,核心的只有一条,其中递归次数相关的变量是自然数类型(nat,在PFPL中,也可以通过在相关表达式或者变量头上加上一个横线来表示,如 x ‾ \overline{x} x),剩下的变量是相同的任意类型,从递归的语义本身也可以推测:
Γ ⊢ e : n a t     Γ ⊢ e 0 : τ     Γ , x : n a t , y : τ ⊢ e 1 : τ Γ ⊢ r e c { τ } ( e ; e 0 ; x . y . e 1 ) : τ \frac{\Gamma\vdash e:nat\ \ \ \Gamma\vdash e_0:\tau\ \ \ \Gamma,x:nat,y:\tau\vdash e_1:\tau}{\Gamma\vdash rec\{\tau\}(e;e_0;x.y.e_1):\tau} Γrec{τ}(e;e0;x.y.e1):τΓe:nat   Γe0:τ   Γ,x:nat,y:τe1:τ
dynamics of recursion。递归的动力学。包含了两条核心的结构动力学。第一个代表了,如果递归次数是0(用 z z z表示),那么递归的初值就是其结果。第二个代表了如果增加一次迭代次数(用 s ( e ) s(e) s(e)表示, s s s代表+1),那么就是用当前归约的结果再执行一次归约的逻辑 e 1 e_1 e1。表达为如下的结构动力学:
r e c { τ } ( z ; e 0 ; x . y . e 1 ) ⟼ e 0 \frac{}{rec\{\tau\}(z;e_0;x.y.e_1)\longmapsto e_0} rec{τ}(z;e0;x.y.e1)e0

s ( e )   v a l r e c { τ } ( s ( e ) ; e 0 ; x . y . e 1 ) ⟼ [ e , r e c { τ } ( e ; e 0 ; x . y . e 1 ) / x , y ] e 1 \frac{s(e)\ val}{rec\{\tau\}(s(e);e_0;x.y.e_1)\longmapsto [e,rec\{\tau\}(e;e_0;x.y.e_1)/x,y]e_1} rec{τ}(s(e);e0;x.y.e1)[e,rec{τ}(e;e0;x.y.e1)/x,y]e1s(e) val

syntax of system T。system T的语义。相比一般的编程语言system T的语义非常简单,除了变量的定义、零的定义、函数的定义与调用、递归的定义之外,唯一一个可以改变变量的值的语法只有 s ( e ) s(e) s(e),用以给一个表达式的值+1。即便是最为基本的加减乘数都是没有的。

definability of system T。在system T中可定义性。如果一个参数和返回值都是自然数的数学函数 f f f可以在system T中被定义,即可以找到表达式 e f ( n ‾ ) ≡ f ( n ) ‾ : n a t e_f(\overline{n})\equiv\overline{f(n)}:nat ef(n)f(n):nat,那么我们就说这一函数在system T中是可被定义的。在system T中可定义说明这一函数的执行的有穷的,不会出现无限的递归(或者循环,二者等价)。system的这一性质也被称作termination theorem(终止定理),对于一个system T中的表达式 e : τ e:\tau e:τ,一定有数值 v v v,使得 e ≡ v : τ e\equiv v:\tau ev:τ。这一定理的证明主要是用递归语法来执行数学归纳法。


Chapter 10: Product Types

这一章提出一个叫做product(积)的概念。类似于一般编程语言中的元组或者数组的概念,将一些有限的变量组合起来。而product type是将元组中每一元素的类型组合起来产生的积类型。

binary products。二元积。二元积本质上为两个表达式(称作product的component)的有序组合,表达为 ⟨ e 1 , e 2 ⟩ \langle e_1,e_2 \rangle e1,e2,或者写成operator的形式 p a i r ( e 1 ; e 2 ) pair(e_1;e_2) pair(e1;e2)。二元积的的类型本质上就是两个表达式的类型组合在一起,写成 τ 1 × τ 2 \tau_1 \times \tau_2 τ1×τ2或者 × ( τ 1 ; τ 2 ) \times(\tau_1;\tau_2) ×(τ1;τ2)的形式。二元组有两种操作,分别是取二元组的左右值,取左值写成 e . l e.l e.l或者 p r [ l ] ( e ) pr[l](e) pr[l](e),取右值写成 e . r e.r e.r或者 p r [ r ] ( e ) pr[r](e) pr[r](e)

nullary products。空积。代表空的元组,空的元组也是值的一种,类似于一般编程语言中的None或者null的语法。

finite products。有限积。将有限的表达式按照顺序组合起来,每一个表达式都有自己的类型,这些类型构成了有限积的类型。有限积中表达式的索引用 I = { i 1 , . . . , i n } I=\{i_1,...,i_n\} I={i1,...,in}表示。每一个索引对应的表达式类型和表达式表达为 i k ↪ τ k i_k \hookrightarrow \tau_k ikτk,和 i k ↪ e k i_k \hookrightarrow e_k ikek ↪ \hookrightarrow 代表了“映射”或者对应的关系,在PFPL中,这一符号的含义很丰富,在这里代表索引对应的元素,也可以代表函数输入输出的关系,也可以代表递归(迭代)次数和迭代结果之间的关系,等等。有限积的表达形式和其类型的表达方式与二元积是一样的。当然也有取对应位置的值的操作,表达为 p r [ i ] ( e ) pr[i](e) pr[i](e)或者 e . i e.i e.i


Chapter 11: Sum Types

Sum Types处理有选择的执行过程。一个表达式可以带入不同的分支中的不同的母表达式中(当然要和表达式中的变量的类型一致)。那么分支的索引加上表达式就也就是一个表达式被带入到不同分支的所有可能。sum type就是不同分支中表达式带入到的变量的type的集合。product type代表同时具有一系列类型,sum type代表从一系列类型中选一个类型。sum type的表达式可以用来表达分支、枚举之类的语法。

binary sums。二元和。表达了表达式向不同分支中母表达式的带入。可以写成case表达式,写成 c a s e ( e 0 ; x 1 . e 1 ; x 2 . e 2 ) case(e_0;x_1.e_1;x_2.e_2) case(e0;x1.e1;x2.e2) c a s e   e 0 { l . x 1 ↪ e 1 ∣ r . x 2 ↪ e 2 } case\ e_0\{l.x_1\hookrightarrow e_1|r.x_2 \hookrightarrow e_2\} case e0{l.x1e1r.x2e2}的形式。 l . x 1 l.x_1 l.x1 r . x 2 r.x_2 r.x2是注入(injection)表达式,包含了被替换的变量名称( x 1   x 2 x_1\ x_2 x1 x2)和被替换变量所处的分支的名称( l   r l\ r l r)。也可以写成operator的形式, i n [ l ] { τ 1 ; τ 2 } ( e ) in[l]\{\tau_1;\tau_2\}(e) in[l]{τ1;τ2}(e)。注入表达式也用以表达要注入的表达式, e 0 e_0 e0可以表达为类似的形式 l . e l.e l.e,代表将表达式 e e e带入到 l l l分支的变量 x 1 x_1 x1中,并且给出表达式 e 1 e_1 e1。这个过程可以表达为一个核心的动力学断言:
c a s e   l . e { l . x 1 ↪ e 1 ∣ r . x 2 ↪ e 2 } ⟼ [ e / x 1 ] e 1 case\ l.e\{l.x_1\hookrightarrow e_1|r.x_2 \hookrightarrow e_2\}\longmapsto [e/x_1]e_1 case l.e{l.x1e1r.x2e2}[e/x1]e1
其中,替换(注入)与被注入的变量类型要一致。

nullary sums。空和。与空积不同,空和不产生任何意义的值。

sum type。和类型。代表注入表达式的type,其中包含了所有可以被注入的变量的type。对于前文的例子中, x 1 : τ 1     x 2 : τ 2 x_1:\tau_1\ \ \ x_2:\tau_2 x1:τ1   x2:τ2,那么其对应的注入表达式对应的类型满足对应的静力学规则:
Γ ⊢ e : τ 1 Γ ⊢ l . e : τ 1 + τ 2 \frac{\Gamma\vdash e:\tau_1}{\Gamma\vdash l.e:\tau_1+\tau_2} Γl.e:τ1+τ2Γe:τ1
injection表达式是对应分支的被注入变量和分支名字的组合。injection表达式的类型是所有分支的中被替代变量的类型的组合,中间用 + + +连接,或者表达为 + { τ 1 ; τ 2 } +\{\tau_1;\tau_2\} +{τ1;τ2}的形式。这一type的制定规则保证了静力学的type safety中被注入表达式与注入表达式之间的type一致(因为静力学阶段无法知道要注入的表达式是什么type,所以干脆就先把潜在的所有type都组合起来)。

finite sums。有限和。与有限积类似,分支超过两个的sum。在有限和中注入表达式为 i . e i.e i.e,也可以表达为 i n [ i ] { τ ⃗ } ( e ) in[i]\{\vec{\tau}\}(e) in[i]{τ }(e)。其中 τ ⃗ \vec{\tau} τ 代表了所有分支中被替代变量的类型, i i i代表被注入的分支。


Chapter 12: Constructive Logic

建设性逻辑。利用数学的推理方法来逻辑推理。即要证明一个命题是正确的,那就给出一个证明,如果要证明一个命题是错误的,那么只需要给出一个反例就好了。所谓的证明,就是以公理或者假设为源头的推导。这种证明方法不能证明所有的命题,有些命题可能(在有限时间内)证明和反例都给不出来(这类问题被称为undecided,或者称作open problem,反之可以给出真值的问题被称为decidable),这是建设性逻辑必然需要面对和接受的情况。

constructive logic。建设性逻辑。使用 ϕ \phi ϕ来代表一个命题。使用 ϕ   t r u e \phi\ true ϕ true代表命题 Φ \Phi Φ是正确的,是可以给出一个证明的。当然,一个命题的证明可能存在以其他命题存在证明为前提,表达为 ϕ 1   t r u e , . . . , ϕ n   t r u e ⊢ ϕ   t r u e \phi_1\ true,...,\phi_n\ true \vdash \phi\ true ϕ1 true,...,ϕn trueϕ true。这是假设命题,满足假设命题的一系列属性。

propositional logic。命题逻辑。使用一系列的语法符号来代表。命题符号 ϕ \phi ϕ可以被一系列命题逻辑的表达式替换。这些表达式中 ⊤ \top 代表真理; ⊥ \bot 代表谬误; ∧ ( ϕ 1 ; ϕ 2 ) \wedge(\phi_1;\phi_2) (ϕ1;ϕ2)或者 Φ 1 ∧ Φ 2 \Phi_1\wedge \Phi_2 Φ1Φ2代表合取,当两个命题都为真(存在证明)时,那么两个命题的合取也为真; ∨ ( ϕ 1 ; ϕ 2 ) \vee(\phi_1;\phi_2) (ϕ1;ϕ2)或者 ϕ 1 ∨ ϕ 2 \phi_1\vee \phi_2 ϕ1ϕ2代表析取,当两个命题中有一个命题为真,那么两个命题的析取也为真; ⊃ ( ϕ 1 ; ϕ 2 ) \supset(\phi_1;\phi_2) (ϕ1;ϕ2)或者 ϕ 1 ⊃ ϕ 2 \phi_1\supset \phi_2 ϕ1ϕ2是暗含的意思,当 ϕ 1 \phi_1 ϕ1是真的时候, ϕ 2 \phi_2 ϕ2也是真的,或者说 ϕ 2 \phi_2 ϕ2的证明包含在 ϕ 1 \phi_1 ϕ1的证明中。这里这里说的都是命题逻辑中的introduction规则,表达了带有连词命题的子命题的真值与母命题真值之间的关系。之后会介绍其elimination形式的规则,从带有连接词的母命题真值推导子命题的真值。

truth。真理。有一个公理,真理必然是正确的 Γ ⊢ ⊤   t r u e ‾ \overline{\Gamma\vdash \top\ true} Γ true

conjunction。合取。一个带有合取的命题是真的,那么其合取命题中的子命题也是真的。表达为 Γ ⊢ ϕ 1 ∧ ϕ 2   t r u e Γ ⊢ ϕ 1   t r u e \frac{\Gamma\vdash \phi_1\wedge \phi_2\ true}{\Gamma\vdash \phi_1\ true} Γϕ1 trueΓϕ1ϕ2 true Γ ⊢ ϕ 1 ∧ ϕ 2   t r u e Γ ⊢ ϕ 2   t r u e \frac{\Gamma\vdash \phi_1\wedge \phi_2\ true}{\Gamma\vdash \phi_2\ true} Γϕ2 trueΓϕ1ϕ2 true

implication。暗含。暗含代表了一个命题为真可以作为另一个命题为真的假设前提,表达为 Γ , ϕ 1   t r u e ⊢ ϕ 2   t r u e Γ ⊢ ϕ 1 ⊃ ϕ 2   t r u e \frac{\Gamma,\phi_1\ true\vdash\phi_2\ true}{\Gamma\vdash \phi_1\supset\phi_2\ true } Γϕ1ϕ2 trueΓ,ϕ1 trueϕ2 true。如果作为假设前提的命题实际上就是真命题,那么被暗含的命题,肯定也是真命题,是可证的。表达为 Γ ⊢ ϕ 1 ⊃ ϕ 2   t r u e    Γ ⊢ ϕ 1   t r u e Γ ⊢ ϕ 2   t r u e \frac{\Gamma\vdash \phi_1\supset\phi_2\ true\ \ \Gamma\vdash\phi_1\ true}{\Gamma\vdash\phi_2\ true} Γϕ2 trueΓϕ1ϕ2 true  Γϕ1 true。后面这个rule称为elimination rule,表达了从母命题到子命题的关系。

disjunction。析取。析取命题中的子命题为真都可以推导出某个其他命题为真,那么析取命题本身确实为真,那么那个其他命题也是真。
Γ ⊢ ϕ 1 ∨ ϕ 2   t r u e    Γ , ϕ 1   t r u e ⊢ ϕ   t r u e    Γ , ϕ 2   t r u e ⊢ ϕ   t r u e Γ ⊢ ϕ   t r u e \frac{\Gamma\vdash\phi_1\vee\phi_2\ true\ \ \Gamma,\phi_1\ true\vdash\phi\ true\ \ \Gamma,\phi_2\ true\vdash\phi\ true}{\Gamma\vdash\phi\ true} Γϕ trueΓϕ1ϕ2 true  Γ,ϕ1 trueϕ true  Γ,ϕ2 trueϕ true
negation。否定。命题 ϕ \phi ϕ的否定表达为 ¬ ϕ \neg\phi ¬ϕ ¬ ϕ   t r u e \neg\phi\ true ¬ϕ true当且仅当命题 ϕ \phi ϕ存在一个反例,也就是 ϕ \phi ϕ真值为假。

propositions-as-types。命题作为类型。将命题的证明接驳到之前的静力学和动力学理论当中,使得可以用程序来执行命题的证明。使用 p : ϕ p:\phi p:ϕ来表达相关语法,其中 ϕ \phi ϕ是命题, p p p代表这一命题的证明(证明术语),称作proof term。

syntax of proof terms。证明术语的语法。表达了命题证明之间的产生关系,即怎么组合多个子命题的证明产生一个带有连接词母命题的证明,以及怎么从一个带有连接词的母命题中提取一个更小的命题的证明。因为在建设性命题中,真值为真本质上就是存在命题,所以证明术语的语法中也隐含了带连接符的命题中母命题和子命题的真值关系。从静力学和动力学的角度来说,合取本质上是一个product type,析取本质上是一个sum type,暗含本质上是一个function type。真理本质上是空积,谬论本质上是空和。部分规则表达为如下形式,其中introduction形式(从子命题的证明中推导出母命题的证明)本质上是二元组、case表达式、函数定义;其中投影、注入、函数调用为为elimination形式(从母命题的证明中推导出子命题的证明):
Γ ⊢ ⟨ ⟩ : ⊤ ‾ \overline{\Gamma\vdash \langle\rangle:\top} Γ:

Γ ⊢ p 1 : ϕ 1    Γ ⊢ p 2 : ϕ 2 Γ ⊢ ⟨ p 1 , p 2 ⟩ : ϕ 1 ∧ ϕ 2 \frac{\Gamma\vdash p_1:\phi_1\ \ \Gamma\vdash p_2:\phi_2}{\Gamma\vdash\langle p_1,p_2 \rangle:\phi_1\wedge \phi_2} Γp1,p2:ϕ1ϕ2Γp1:ϕ1  Γp2:ϕ2

Γ ⊢ p : ϕ 1 ∧ ϕ 2 Γ ⊢ p . l : ϕ 1 \frac{\Gamma\vdash p:\phi_1\wedge \phi_2}{\Gamma\vdash p.l:\phi_1} Γp.l:ϕ1Γp:ϕ1ϕ2

Γ , x : ϕ 1 ⊢ p 2 : ϕ 2 Γ ⊢ λ ( x ) p 2 : ϕ 1 ⊃ ϕ 2 \frac{\Gamma,x:\phi_1\vdash p_2:\phi_2}{\Gamma\vdash \lambda(x)p_2:\phi_1\supset\phi_2} Γλ(x)p2:ϕ1ϕ2Γ,x:ϕ1p2:ϕ2

Γ ⊢ p : ϕ 1 ⊃ ϕ 2    Γ ⊢ p 1 : ϕ 1 Γ ⊢ p ( p 1 ) : ϕ 2 \frac{\Gamma\vdash p:\phi_1\supset\phi_2\ \ \Gamma\vdash p_1:\phi_1}{\Gamma\vdash p(p_1):\phi_2} Γp(p1):ϕ2Γp:ϕ1ϕ2  Γp1:ϕ1

Γ ⊢ p : ⊥ Γ ⊢ c a s e   p { } : ϕ \frac{\Gamma\vdash p:\bot}{\Gamma\vdash case\ p\{\}:\phi} Γcase p{}:ϕΓp:

Γ ⊢ p 1 : ϕ 1 Γ ⊢ l ⋅ p 1 : ϕ 1 ∨ ϕ 2 \frac{\Gamma\vdash p_1:\phi_1}{\Gamma\vdash l·p_1:\phi_1\vee\phi_2} Γlp1:ϕ1ϕ2Γp1:ϕ1

Γ ⊢ p : ϕ 1 ∨ ϕ 2    Γ , x 1 : ϕ 1 ⊢ p 1 : ϕ    Γ , x 2 : ϕ 2 ⊢ p 2 : ϕ Γ ⊢ c a s e   p { l . x ↪ p 1 ∣ r . x 2 ↪ p 2 } : ϕ \frac{\Gamma\vdash p:\phi_1\vee\phi_2\ \ \Gamma,x_1:\phi_1\vdash p_1:\phi\ \ \Gamma,x_2:\phi_2\vdash p_2:\phi}{\Gamma\vdash case\ p\{l.x\hookrightarrow p_1|r.x_2 \hookrightarrow p_2\}:\phi} Γcase p{l.xp1r.x2p2}:ϕΓp:ϕ1ϕ2  Γ,x1:ϕ1p1:ϕ  Γ,x2:ϕ2p2:ϕ

Gentzen’s Principle。根岑原理。根岑原理认为,在introduction形式(由子命题证明母命题)对母命题的证明中可以通过elimination形式的rule还原出子命题的证明。即对于命题逻辑来说,子命题的证明可以在introduction form的规则中用以产生母命题的证明,而母命题可以进一步利用elimination form的规则复原对于子命题的证明。反之,对于母命题的证明可以用以在elimination form的规则中产生对于其子命题的证明,而通过introduction form的规则又可以从这些子命题中复原出对于母命题的证明。


Chapter 13: Classical Logic

经典逻辑。与建设性逻辑(证明命题为真就给出证明,证明命题为假就给出反例)不同。经典逻辑无论证明命题为真还是命题为假都使用反证法来证明。主要的区别在想证明一个命题为真,那就先假设这个命题为假,然后推导出一个矛盾。在经典逻辑中,命题的真假是具有对称性的、是没有open problem的、非真即假的。经典逻辑对于命题为假的证明的严格程度和建设性逻辑是一样的,但是对于命题为真的证明是不用给出真正意义上的证明的,这会使得经典逻辑对于真命题的证明比建设性逻辑更弱。

provability and refutability。可证明性与可反驳性。使用 ϕ   t r u e \phi\ true ϕ true来表达命题 ϕ \phi ϕ是真的、可以证明的。使用 ϕ   f a l s e \phi\ false ϕ false来证明命题 ϕ \phi ϕ是假的、是可以找出反驳的。使用 # \# #来代表一个矛盾。可以使用假设命题来表达与命题真假相关的断言 J J J,表达为:
ϕ 1   f a l s e , . . . , ϕ m   f a l s e    ψ 1   t r u e , . . . , ψ n   t r u e ⊢ J \phi_1\ false,...,\phi_m\ false\ \ \psi_1\ true,...,\psi_n\ true\vdash J ϕ1 false,...,ϕm false  ψ1 true,...,ψn trueJ
可以将所有假命题相关的假设表示为集合 △ \bigtriangleup ,将所有真命题相关的假设表示为集合 Γ \Gamma Γ。那么这个假设断言可以表达为: △   Γ ⊢ J \bigtriangleup\ \Gamma\vdash J  ΓJ

contradiction。矛盾。经典逻辑中计算命题真值的核心概念。当在相同的假设下,如果推导出一个命题同时为真和假,这就产生了一个矛盾,可以表达为rule:
△   Γ ⊢ ϕ   f a l s e     △   Γ ⊢ ϕ   t r u e △   Γ ⊢ # \frac{\bigtriangleup\ \Gamma\vdash\phi\ false\ \ \ \bigtriangleup\ \Gamma\vdash\phi\ true}{\bigtriangleup\ \Gamma\vdash\#}  Γ# Γϕ false    Γϕ true
而想证明一个命题是真的或者假的,那就先假设一个命题是假的或者真的,并且在此基础上可以推导出一个矛盾( ⊢ \vdash 有“可推导”的意思),表达为:
△ , ϕ   f a l s e    Γ ⊢ # △    Γ ⊢ ϕ   t r u e \frac{\bigtriangleup,\phi\ false\ \ \Gamma\vdash\#}{\bigtriangleup\ \ \Gamma\vdash\phi\ true}   Γϕ true,ϕ false  Γ#

这本质上是一个命题为真的证明,被称作proof;
△ , ϕ   t r u e    Γ ⊢ # △    Γ ⊢ ϕ   f a l s e \frac{\bigtriangleup,\phi\ true\ \ \Gamma\vdash\#}{\bigtriangleup\ \ \Gamma\vdash\phi\ false}   Γϕ false,ϕ true  Γ#

这本质上是一个命题为假的证明,被称作refutation。

这种不直接给出证明,而是通过先假设一个相反的真值再推导出矛盾的证明方式,被称作间接证明。

introduction and elimination form。引入与消除形式。如前文所述,在不同领域中有不同的含义。在经典逻辑的rule中,introduction form表达了一个带有连接词的母表达式为真的时候子表达式的真值要求,这与建设性逻辑一致。而elimination form表达了当母表达式为假的时候,子表达式的真值要求,这与建设性逻辑完全不一样。

conjunction。合取。其introduction form的rule为 △   Γ ⊢ ϕ 1   t r u e    △   Γ ⊢ ϕ 2   t r u e △   Γ ⊢ ϕ 1 ∧ ϕ 2   t r u e \frac{\bigtriangleup\ \Gamma\vdash\phi_1\ true\ \ \bigtriangleup\ \Gamma\vdash\phi_2\ true}{\bigtriangleup\ \Gamma\vdash\phi_1\wedge\phi_2\ true}  Γϕ1ϕ2 true Γϕ1 true   Γϕ2 true,与constructive logic一致(后文不再赘述)。elimination form的rule为 △   Γ ⊢ ϕ 1   f a l s e △   Γ ⊢ ϕ 1 ∧ ϕ 2   f a l s e \frac{\bigtriangleup\ \Gamma\vdash\phi_1\ false}{\bigtriangleup\ \Gamma\vdash\phi_1\wedge\phi_2\ false}  Γϕ1ϕ2 false Γϕ1 false ϕ 2 \phi_2 ϕ2同理),代表了命题的合取是false,需要每一个子命题是false的。

disjunction。析取。其elimination form的rule为 △   Γ ⊢ ϕ 1   f a l s e    △   Γ ⊢ ϕ 2   f a l s e △   Γ ⊢ ϕ 1 ∨ ϕ 2   f a l s e \frac{\bigtriangleup\ \Gamma\vdash\phi_1\ false\ \ \bigtriangleup\ \Gamma\vdash\phi_2\ false}{\bigtriangleup\ \Gamma\vdash\phi_1\vee\phi_2\ false}  Γϕ1ϕ2 false Γϕ1 false   Γϕ2 false

negation。否定。一个命题的否定会反转这一命题的真值。比如 △   Γ ⊢ ϕ   t r u e △   Γ ⊢ ¬ ϕ   f a l s e \frac{\bigtriangleup\ \Gamma\vdash\phi\ true}{\bigtriangleup\ \Gamma\vdash\neg\phi\ false}  Γ¬ϕ false Γϕ true

implication。暗含。假设一个命令成立的时候另外一个命题也成立,那么这两个命题之间的暗含关系就成立。当作为假设的命题成立时,另外一个命题不成立,那么二者之间的暗含关系就不成立,这是暗含关系的elimination form。表达为 △   Γ ⊢ ϕ 1   t r u e    △   Γ ⊢ ϕ 2   f a l s e △   Γ ⊢ ϕ 1 ⊃ ϕ 2   f a l s e \frac{\bigtriangleup\ \Gamma\vdash\phi_1\ true\ \ \bigtriangleup\ \Gamma\vdash\phi_2\ false}{\bigtriangleup\ \Gamma\vdash\phi_1\supset\phi_2\ false}  Γϕ1ϕ2 false Γϕ1 true   Γϕ2 false

explicit syntax for proofs and refutations。显式证明与反驳的语法。与建设性命题中propositions-as-types的方式类似。将命题类比于type。因为在经典逻辑中false和true是对称的,反例也被显式表达出来。在显式表达证明(proof)和反驳(refutation)的语法中, △   Γ ⊢ p : ϕ \bigtriangleup\ \Gamma\vdash p:\phi  Γp:ϕ,代表 p p p是(真)命题 ϕ \phi ϕ的proof; △   Γ ⊢ k ÷ ϕ \bigtriangleup\ \Gamma\vdash k\div\phi  Γk÷ϕ,代表 k k k是(假)命题 ϕ \phi ϕ的refutation; △   Γ ⊢ k # p \bigtriangleup\ \Gamma\vdash k\# p  Γk#p代表针对同一个命题同时存在证明 p p p和反驳 k k k,产生了冲突。将证明与反驳视为表达式,命题的连接词视为operator。由此可以将经典逻辑的推理过程视为语法的逻辑,接驳到静力学和动力学系统中,其定义方式与建设性逻辑中的propositions-as-types的方式类似。矛盾在经典逻辑中比较重要。使用显式语法表达命题证明为: c c r ( u . ( k # p ) ) ccr(u.(k\#p)) ccr(u.(k#p)),命题反驳为: c c p ( x . ( k # p ) ) ccp(x.(k\#p)) ccp(x.(k#p))。以前者为例,其静力学可以表达为:
△ , u ÷ ϕ   Γ ⊢ k # p △   Γ ⊢ c c r ( u . ( k # p ) ) : ϕ \frac{\bigtriangleup,u\div\phi\ \Gamma\vdash k\#p}{\bigtriangleup\ \Gamma\vdash ccr(u.(k\#p)):\phi}  Γccr(u.(k#p)):ϕ,u÷ϕ Γk#p
代表如果存在证明命题 ϕ \phi ϕ为假的反例 u u u,可以推导出矛盾 k # p k\#p k#p,那么这一过程就可以作为命题为真的证明。这一假设+推导出矛盾的过程可以直接简写为 c c r ( u . ( k # p ) ) ccr(u.(k\#p)) ccr(u.(k#p)),并且作为命题为真的证明。

proof dynamics。证明动力学。一种简化矛盾关系的动力学。其主要的好处是消除矛盾关系 k # p k\#p k#p的反驳 k k k和证明 p p p中没有间接证明(反证法,或者说没有 c c r ccr ccr c c p ccp ccp语句),或者尽可能消去连接词。以 c c p ccp ccp表达式为例,其可以表达为一个替换,以消除 c c p ccp ccp表达式:
c c p ( x . ( k 1 # p 1 ) # p 2 ⟼ [ p 2 / x ] k 1 # [ p 2 / x ] p 1 ccp(x.(k_1\#p_1)\#p_2\longmapsto[p_2/x]k_1\#[p_2/x]p_1 ccp(x.(k1#p1)#p2[p2/x]k1#[p2/x]p1
law of the excluded middle。排中率,在一个命题要么是真的要么是假的,没有中间地带。表达为 ϕ ∨ ¬ ϕ   t r u e \phi\vee\neg\phi\ true ϕ¬ϕ true。书中给出了这一问题的证明,使用了大量经典逻辑的规则以及假设断言的规则。整体上先将 ϕ ∨ ¬ ϕ   f a l s e \phi\vee\neg\phi\ false ϕ¬ϕ false作为一切规则的假设。比如证明引入了基于反射性的公理 ϕ ∨ ¬ ϕ   f a l s e ⊢ ϕ ∨ ¬ ϕ   f a l s e ‾ \overline{\phi\vee\neg\phi\ false\vdash\phi\vee\neg\phi\ false} ϕ¬ϕ falseϕ¬ϕ false。以及基于假设断言中weaken性质的公理 ϕ ∨ ¬ ϕ   f a l s e , ϕ   t r u e ⊢ ϕ ∨ ¬ ϕ   f a l s e ‾ \overline{\phi\vee\neg\phi\ false,\phi\ true\vdash\phi\vee\neg\phi\ false} ϕ¬ϕ false,ϕ trueϕ¬ϕ false以及 ϕ ∨ ¬ ϕ   f a l s e , ϕ   t r u e ⊢ ϕ   t r u e ‾ \overline{\phi\vee\neg\phi\ false,\phi\ true\vdash\phi\ true} ϕ¬ϕ false,ϕ trueϕ true。作为推理的起点,然后使用前文所述的有关经典逻辑的rule在这一假设下推导出一个矛盾,形如 ϕ ∨ ¬ ϕ   f a l s e ⊢ # \phi\vee\neg\phi\ false\vdash\# ϕ¬ϕ false#。最终就可以得到排中律正确的证明。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值