h5i
本中文版由作者借助 AI 翻译而成。作者并非中文母语者,译文未经人工逐句校对,可能存在错误。如发现问题,请在 GitHub 上提交 issue。

MiniLean4

从零实现交互式定理证明器

一个 Lean 4 风格的证明内核,从零开始构建。起点只有五种项和八条类型规则;到最后加入归纳类型、策略语言,以及维系整个系统一致性的宇宙层级。每一部分都对应一段小巧的 Rust 实现,一个下午就能读完。

证明即程序。内核负责检查。其余皆不可信。

# 命题上的多态恒等函数:对每个 P,都有 P -> P。
goal forall (P : Sort 0), P -> P
intro P
intro p
exact p
qed

这是真正的内核,编译成 WebAssembly,正在检查本书的第一个定理。修改脚本,再运行一次。

本书是什么

Lean、Coq、Agda 这类交互式定理证明器(interactive theorem prover)都建立在一个很小的核心之上:一个内核(kernel),用来判定某个项是否具有给定的类型。其余一切,包括策略、记法和自动化,都只是脚手架,负责生成交给内核检查的项。只要内核是对的,别处的错误至多让系统证不出某个定理,却绝不会让它接受一个错误的定理。

MiniLean4 是一个教学规模的证明助手(proof assistant)内核:它采用与 Lean 4、Coq、Agda 用于形式化验证(formal verification)的同一类依赖类型理论,只是裁剪到几个 Rust 文件就能容纳的程度。如果你想弄清 Lean 4 如何检查证明、Curry-Howard 对应在实践中意味着什么、形式化验证工具的可信从何而来,本书把这套机制毫无保留地摆在你面前。

本书的目标是把这个内核讲具体。每一章先在纸上引入一个想法,给出精确的陈述,再展示实现它的 Rust 代码。整个实现,包括内核、策略和解析器,不到三千行,没有任何依赖,本书会全部讲到。

本书自成一体,读者只需能读懂递归函数,并了解一点集合记法。不要求事先接触过类型论或 Lean,不过熟悉 Lean 的读者会发现许多似曾相识的内容。

如何阅读

命题逻辑的内核

  1. 1命题即类型为什么检查证明和给程序做类型检查是同一件事。
  2. 2项的语言五种项,以及表示它们的 Rust 枚举。
  3. 3类型规则上下文、判断,以及定义良型项的八条规则。
  4. 4作为逻辑的类型规则自然演绎、公式到类型的翻译,以及一致性的含义。
  5. 5类型检查算法把规则变成 Infer 与 Check,并逐行对照 typecheck.rs。
  6. 6逐步示例检查器处理正确证明、错误证明和转换的逐步追踪。

扩展内核

  1. 7归纳类型 I:自然数常量、定义,以及同时提供递归和归纳的递归子。
  2. 8归纳类型 II:通用方法树、列表、向量,以及生成任意递归子的过程。
  3. 9相等也是归纳类型Eq、传输、定义相等与命题相等,以及 0 + n = n 的证明。
  4. 10策略:交互式地构造证明项目标、洞,以及 intro、apply、induction、rw 如何构造项。

内部机制

  1. 11替换、捕获与 α 等价内核 bug 藏身的操作,以及 substitution.rs 如何避开它们。
  2. 12归约与转换β、δ、ι;作为数据的计算规则;弱头范式。

基础

  1. 13宇宙:为什么是 Sort u?Type : Type 不一致;底层非谓词的层级则一致。
  2. 14系统的性质类型唯一性、类型保持性、强规范化、一致性。

附录

  1. A“证明即项”的证明翻译定理的完整证明。
  2. Bα 等价算法的正确性两种定义都在计算 de Bruijn 形式。
  3. CHurkens 悖论Type : Type 之下类型为 False 的闭项。
  4. D一致性的证明没有闭项居于 forall P, P。
  5. Eleanmini 语言脚本语言的语法、命令与策略。
  6. F记号与术语表本书使用的每个符号和术语。
  7. 参考文献

第一部分为一个依赖类型论构建类型检查器,并说明它就是某种逻辑的证明检查器。第二部分加入归纳类型(自然数、树、列表、向量和相等),以及替你写出证明项的策略语言。第三部分打开前两部分一直依赖的黑箱:替换、α 等价和归约,内核的错误往往藏在这里。第四部分解释宇宙为何如此构造,并陈述元理论。附录包含完整的证明、为宇宙设计提供依据的悖论,以及脚本语言的参考手册。

全书中你会遇到四种交互元素。

  • 演练场运行内核:编辑脚本,按下运行,然后阅读输出记录。
  • 浏览器(explorer)展示内核眼中的项:语法树、逐条规则的类型推导、逐步进行的归约、每个变量属于哪个绑定子,以及每条策略之后的证明状态。每个浏览器都是实时的:改动项,内核就会重新计算。
  • 步进器逐步执行一个算法,展示每一步之后的状态。
  • 调用树展示类型检查器在某个项上发起的递归调用的精确序列,并标出每次调用对应的类型规则。

标有代码中的提示框指向实现刚才所定义内容的 Rust 函数。练习附有解答,默认折叠,需要时再展开。

自己运行代码

代码仓库包含内核、一个命令行运行器,以及本书用到的示例脚本。

cargo run -- examples/identity.leanmini
cargo run -- examples/nat-reflexivity.leanmini
cargo run -- examples/zero-add.leanmini
cargo run -- examples/generic-list.leanmini
cargo run -- examples/generic-vec.leanmini
cargo test

不带参数运行 cargo run 会启动一个交互式会话,逐行接受同样的命令,这门语言由附录 E 描述。

源码的组织顺序与本书一致。

文件 内容 章节
src/term.rs 项的表示 2
src/typecheck.rs 类型推断与类型检查 5、6
src/substitution.rs 自由变量、替换、α 等价 11
src/reduction.rs 弱头范式、规范化、定义相等 12
src/declaration.rs 签名:常量、定义、归纳类型元数据 7、8
src/inductive/ 检查归纳声明并生成递归子 8
src/proof.rs 目标、证明状态与策略 10
src/syntax.rs 脚本语言的解析器 附录 E
src/main.rs 命令行运行器 附录 E