想象你是跨河大桥的施工总工程师。你不能拍拍胸脯说「桥一定不会塌」就交工——你必须拿出设计图纸、每一根钢梁的规格书、每一道焊缝的检测记录,最后由监理逐项盖章验收。数学证明的本质也是这样一座桥:前提是此岸,结论是彼岸,中间每一个推导步骤都是一块桥板。只要有一块板不合格,整座桥就站不住。Lean,就是这套「施工与验收」的数字化系统——它不信任你的口头承诺,只检查你亲手铺下的每一块桥板。这篇文章从「造桥」视角带你认识 Lean 的依值类型论、定理定义、证明书写、战术模式、归纳类型,以及为什么 AI 定理证明社区把它当成最顺手的工地。学完你再回头看 Lean 代码,就像工程师看施工图,一眼就知道哪里有路、哪里要补板。

岗位关联

对 AI 从业者来说,理解 Lean 意味着拿到一把通向形式化验证与 AI 数学推理的钥匙——无论是训练证明助手,还是做关键代码验证,都能站在机器可检查的确定性地基上。

目录
  1. 可视化演示
  2. 初识 Lean——给证明工地请一位数字监理
  3. 类型论基础——给每一块材料贴上规格标签
  4. 定义与定理——把设计图签进合同
  5. 直接书写证明——一块一块钉桥板
  6. 战术模式——给施工队配全套机械
  7. 归纳类型——用预制件批量生产桥板
  8. AI 定理证明——为什么社区把工地包给机器人
  9. AI 应用场景
  10. Python 演示
  11. 常见误区
  12. 面试题

可视化演示

交互展示AI驱动形式化验证的核心流程:自然语言规约自动生成、符号执行验证管道与反例搜索策略,可视化从需求到证明的自动化闭环。

本节配有交互动效(进入视口后自动加载,约 3KB)。

AI规约自动生成 LLM解析自然语言需求生成形式化规约 类型检查器验证规约语法正确性 Spec = LLM(req) \u2192 \u2713 TypeCheck 从需求文本到形式化规约的自动化转换

初识 Lean——给证明工地请一位数字监理

造大桥最怕什么?不是设计不出来,而是「每个环节都以为别人验过了」。一座悬索桥需要成百上千人协同,任何一环的疏忽都可能酿成事故。数学也一样,一篇论文里的证明可能长达数百页,靠人工评审有时隔很多年才能发现漏洞——四色定理、开普勒猜想这类硬仗都曾让数学家心有余悸。所以数学界一直想找一位不知疲倦、绝不客气的「监理」。

Lean 就是这位数字监理。它是一个交互式定理证明器:你输入一个命题 P,再输入一个证明 p,Lean 的类型检查器会逐字逐句核验 p 是不是 P 的合法证明,就像监理用仪器对每一根钢梁做无损探伤。这一核验是机械的、确定的:过就是过,不过就是不过。市面上还有 Coq、Isabelle/HOL 等定理证明器,但 Lean 的设计哲学非常突出:一个尽可能小的逻辑内核,加一个尽量好用的外部接口。小内核意味着可以被彻底审计,外部接口让 def、theorem、tactic 这些语法糖都只是「翻译」到内核。社区围绕 Lean 建起了 Mathlib——一个覆盖现代数学的统一知识库,规模大得常被形容为「数学的 GitHub」。

Lean 的核心推理规则之一,是逻辑学里最古老的「充分条件假言推理」:只要 A 成立,并且 A 能推出 B,那么 B 就一定成立。这在施工中就像「验收规范」:

学 Lean 的第一课,就是接受一个角色转变:你不再是凭灵感写论文的独行侠,而是带着图纸、随时接受监理抽检的施工队长。Lean 把这种「如临大敌」变成日常,但正因如此,每一座桥都真的站得住。

AA→BB\displaystyle\frac{A \quad A \rightarrow B}{B}
这个式子读作:已知 A 为真,又已知「如果 A 则 B」这条规则为真,那么 B 也可以盖章通过。
  1. 分子左项$A$ 表示已经确认的命题,好比已经检测合格的一批材料。
    AA
  2. 分子右项$A \rightarrow B$ 是一条「如果 A 则 B」的规则,相当于施工规范条文。
    A→BA \rightarrow B
  3. 推理横线横线是「工段验收」动作,把两件已确认的事组合成一条新知识。
    两件已知一件新知\frac{\text{两件已知}}{\text{一件新知}}
  4. 分母结论$B$ 作为结论被写入验收报告,桥又向前进了一跨。
    BB

类型论基础——给每一块材料贴上规格标签

仓库里的钢梁不是一堆铁疙瘩,每根都有铭牌:材质 Q345、长度 12 米、屈服强度 345MPa。没有铭牌的材料不允许上桥。在 Lean 的世界里,每一块「材料」——也就是每一个表达式——也有一张铭牌,叫「类型」。类型决定了这个表达式能用在什么地方,就像钢梁的规格决定了它能架在哪一跨。

这种「值-类型」配对听起来很像编程语言里的变量类型,但 Lean 的类型远比 int、string 强大。当类型可以依赖一个变量的值——比如「对任意自然数 x,x+0=x」这个命题里,命题本身的对象随 x 变化——它就升级成了依值类型。这里藏着一把钥匙:命题即类型(Curry-Howard 对应)。命题是一种类型,命题的证明是这种类型的一个值。于是「证明一个命题」等价于「构造一个特定类型的程序」,就像「把这块钢梁加工成图纸要求的形状」等价于「按规格书一步步施工」。

Lean 的类型本身也有类型:Type : Type 1,而 Type 1 : Type 2……无穷无尽。这不是故弄玄虚,而是为了避免「所有类型都归到自身」导致悖论,就像建筑规范规定「规格书的规格书」也要单独归档——每一层都在上一层登记。宇宙层级是依值类型论的地基,也是新手最容易忽略却最关键的概念之一。

有了铭牌,监理才能验收。Lean 里输入的每一个「值」,都必须先有「类型」这张铭牌,一切后续工作都由这张铭牌展开——这就是它跟传统数学「一个命题孤零零地写在那里」最大的不同。

∀x:N, x+0=x\forall x:\mathbb{N},\ x + 0 = x
这是自然数加法的一条基本性质:任何自然数 n,n 加 0 都等于 n。它不是一个「句子」,而是一个类型——一个等着被构造出来的证明目标。
  1. 全称量词$\forall$ 读作「对所有……」,像施工规范写着「任何一块预制板都……」,把断言推广到无穷多个对象。
    ∀\forall
  2. 变量声明$x:\mathbb{N}$ 表示 x 的类型是自然数,如同铭牌上写明材料编号属于「自然数族」。
    x:Nx:\mathbb{N}
  3. 命题即类型整句 $x+0=x$ 在 Lean 中是一个类型,证明它就是要构造一个「验证程序」,对每个 x 都输出一份合格证明。
    x+0=xx+0=x
  4. 加零等式$x+0=0$ 之所以成立,是因为自然数加法定义里就有「加零不变」这一条,所以它是定义性事实。
    x+0≡xx+0 \equiv x

定义与定理——把设计图签进合同

工程师造桥前,先把「主跨 1200 米」「桥面宽 32 米」写进合同。合同不是愿望,是约束。Lean 里 def 和 theorem 就是签合同的笔:def 定义「材料是什么」,theorem 承诺「必然如此」,而 := 后面跟着的是证明,相当于施工记录。

在 Lean 中,def double (n : ℕ) : ℕ := n + n 定义了「翻倍」这个操作,相当于在仓库里登记一种新材料:名称 double,参数 n,返回值类型 ℕ,实现体 n+n。而 theorem add_zero (n : ℕ) : n + 0 = n 声明了一条桥梁设计承诺:对任意自然数 n,n 加 0 等于 n。注意,声明定理只是「签合同」,合同能不能兑现,还要看后面给出的证明是否通过监理——Lean 的类型检查器——的验收。

Lean 有「环境」概念:只有已经登记进环境的定义和定理才能被后续代码引用,正如监理验收过的桥段才允许通车。#check 命令可以随时查看某个名字的类型,像查档案;example 则用来临时验证一个小命题,不必签「长期合同」。这种「先登记、后引用」的机制保证了整个知识库的每一块砖都来自已验证的来源。

签了合同,监理才会来查。Lean 中定义与定理的边界非常清晰:定义回答「这是什么」,定理回答「必然如何」,证明负责兑现承诺——三者缺一不可,就像设计图、合同和验收报告一起构成一座桥的完整档案。

theorem addZero (n:N):n+0=n\displaystyle \mathrm{theorem}\ \mathrm{addZero}\ (n:\mathbb{N}) : n + 0 = n
这是 Lean 中一条定理的声明骨架:给定理起名 addZero,带上自然数参数 n,冒号后面是要证明的命题。后面的 := 及其右侧的内容,才是真正的施工记录。
  1. theorem 关键字告诉 Lean「接下来是一个待证命题」,相当于在合同封面写上「设计承诺书」。
    theorem\mathrm{theorem}
  2. 定理名 addZero给这座桥起个名字,方便后续代码引用,就像桥名「长江大桥」。
    addZero\mathrm{addZero}
  3. 参数与类型$(n:\mathbb{N})$ 表示这条定理适用于任意自然数 n,是一次「批量承诺」。
    (n:N)(n:\mathbb{N})
  4. 命题签名$n+0=n$ 是承诺的内容;冒号左边的参数和右边命题合在一起,构成了定理的类型。
    n+0=nn+0=n

直接书写证明——一块一块钉桥板

造桥最朴素的方式,是背起桥板从这岸走到那岸,一块块钉死。直接写「证明项」就是这样原始而可靠。在很长一段时间里,数学家使用 Lean 就是这种模式:写出一个表达式,它的类型恰好就是待证命题,表达式的构造过程就是证明过程。

在 Lean 中,一个 P → Q 的证明就是一个函数:给它一个 P 的证明,它返回一个 Q 的证明。比如证明 P → Q → P,只需要写 fun hp => fun hq => hp——收下 hp 和 hq 后就地返回 hp。这段「代码」本身就是证明,因为命题即类型:命题 P→Q→P 是一个类型,而 fun hp => fun hq => hp 是这个类型的构造对象,一个合格的「项」。

这里的 fun(lambda 抽象)对应逻辑里的「蕴含引入」:把前提当成函数参数收进来。函数应用则对应「蕴含消去」。Lean 还提供 apply 做反向应用:目标是 Q,找到一条定理 P→Q,apply 之后目标就变成 P,相当于施工队先看看「要铺到 Q,有没有 P→Q 这条路」。直接写项与使用战术最终都会生成同一个构造对象,就像无论用吊车还是人工,铺上的板都是同一块预制板,只是施工方式不同。

直接写证明确实「手酸」,但它是理解一切的基础——所有花哨的战术,最终都只是帮你拼装这一块块桥板。哪怕你以后只用 tactic 写证明,心里也要清楚:tactic 生成的正是这样的 lambda 项。

λ (hP:P) (hQ:Q), hP:P→Q→P\displaystyle \lambda\ (h_P:P)\ (h_Q:Q),\ h_P \quad : \quad P \to Q \to P
这是证明 P → Q → P 的证明项:两个 lambda 参数分别代表 P 和 Q 的证明,函数体直接返回第一个参数。展开来看,它就是一座一步到位的桥。
  1. lambda 抽象$\lambda$ 用于接收参数,对应逻辑里的「蕴含引入」,也对应 tactic 里的 intro。
    λ\lambda
  2. 第一个参数 hP$(h_P:P)$ 表示收下一个名为 h_P 的证明,它证明命题 P,像接收第一车材料 P。
    (hP:P)(h_P:P)
  3. 第二个参数 hQ$(h_Q:Q)$ 同理收下 Q 的证明,像接收第二车材料 Q。
    (hQ:Q)(h_Q:Q)
  4. 函数体 hP最终返回 h_P,整个表达式就有了类型 $P\to Q\to P$,也就是一座从两个前提直达 P 的桥。
    hPh_P

战术模式——给施工队配全套机械

造大桥光靠人拉肩扛不行,得有起重机、混凝土泵车。Lean 的 tactic 战术模式,就是施工队的机械设备清单。数学家写证明,不再需要像上一节那样从零拼装 lambda 项,而是像指挥施工队一样,一步步下达操作指令。

by 打开战术模式后,Lean 会展示一个「目标看板」:⊢ 左边是当前收集到的前提,右边是还没铺通的桥段。你在看板上看到 P, Q ⊢ P,就知道前提里已经有 P,直接 exact hP 就能收工;看到 ⊢ a + 0 = a,一次 rw [add_zero] 把 a+0 换成 a,目标变成 ⊢ a = a,再 rfl 就直接通车。intro 负责把箭头前的条件收进前提库(跟 lambda 收参数是一回事);apply 反向调用定理;rw 做等价替换;rfl 自动处理自反相等。

由于目标是逐步拆小的,「目标状态」就成了一个实时施工看板。你可以反复试验不同 tactic,Lean 立刻反馈成功或失败,就像工头在看板上看到进度条有没有前进。这种交互感让 Lean 在定理证明器里显得格外「现代」,也让 AI 模型可以在这里不断试错并获得反馈——这一点我们到最后一节还会讲到。

tactic 不是魔法,它们每一个都对应一条确定的逻辑规则,只是把「拼桥板」包装成了顺手好用的机械。所以新手不必被一堆 tactic 名字吓到——核心只需要先掌握 intro、exact、apply、rw、rfl 这五件套,就已经能读能写大多数入门证明了。

P, Q⊢PP,\ Q \vdash P
这是 Lean 里一个典型的证明中间状态:P 和 Q 是已经到手的材料(前提),⊢ 右边 P 是还差最后一块的桥段。只要从材料堆里翻出 P,目标清空,证明完成。
  1. 上下文$P, Q$ 是逗号分隔的已知前提,像施工队已经运到现场的钢材和螺栓。
    P, QP,\ Q
  2. turnstile 符号$\vdash$ 读作「可推出」,把左侧材料仓库和右侧施工目标分开,是看板的中轴线。
    ⊢\vdash
  3. 右侧目标$P$ 是当前需要铺完的桥段。目标恰好是前提之一时,一个 exact 就能让看板清空。
    PP

归纳类型——用预制件批量生产桥板

手工浇筑每一块桥板太慢了。现代造桥用预制构件:一个模具,批量生产,运到现场拼装。归纳类型就是 Lean 的「模具生产线」。数学里最常见的无穷对象——自然数——就是靠这条生产线定义出来的。

在 Lean 中,inductive Nat | zero | succ (n : Nat) 定义自然数:zero 是一块起始板,succ 是把一块板变成下一块板的生产线。这个小小的定义会自动生成自然数归纳原理,也就是数学归纳法:先验收第 0 块板,再证明「第 n 块合格 ⇒ 第 n+1 块合格」,就能保证整座桥无穷无尽地铺下去。归纳类型不只能定义自然数,还能定义列表、树、语法树、带索引的命题——它们共同的特点是:所有值都必须由构造子有限生成,这给了证明器一个「把话说死」的抓手。

配套的递归函数与模式匹配,让「沿着结构做递归」和「沿着结构做归纳」成为同一条流水线的两个方向。比如定义加法:plus zero m := m,plus (succ n) m := succ (plus n m)——第一行处理桥台,第二行处理后继板。这就是为什么 Lean 能表达「无限」:它不靠直觉,靠一条标准化的预制生产线。

理解了归纳类型,你就拿到了 Lean 世界通向「无限」的钥匙。数学里大量证明之所以能走向无穷,不是因为直觉跳跃,而是因为这类模具备好了每一块板的规格。

P(0)∀n, P(n)→P(n+1)∀n, P(n)\displaystyle \frac{P(0)\quad \forall n,\ P(n)\to P(n+1)}{\forall n,\ P(n)}
这就是数学归纳法原理:先验证第 0 块板合格,再证明「任何一块板合格就能推出下一块也合格」,于是所有板都合格。归纳类型把这个原理从「自然数专用」推广到了所有归纳定义的结构上。
  1. 奠基步骤$P(0)$ 表示先验证桥台(n=0)合格,这是归纳法的第一步,也是最容易被忽略的一步。
    P(0)P(0)
  2. 归纳步骤$\forall n,\ P(n)\to P(n+1)$ 表示每一条预制生产线都保证「前一块合格则下一块合格」。
    ∀n, P(n)→P(n+1)\forall n,\ P(n)\to P(n+1)
  3. 全称结论$\forall n,\ P(n)$ 从桥台出发沿流水线无限推进,全桥每一段都合格,目标清空。
    ∀n, P(n)\forall n,\ P(n)

AI 定理证明——为什么社区把工地包给机器人

AI 要学造桥,最怕什么?没有明确验收反馈。你说机器人铺错了,得有个监理立刻指出。Lean 恰好提供了这样的反馈环境:每一步 tactic 都有机器验证结果,目标状态立刻变化,这简直是强化学习天生的训练场。相比之下,如果让 AI 学「读自然语言论文并判断证明对不对」,反馈既延迟又不确定。

正是这个原因,AI 定理证明社区近年大量围绕 Lean 展开。GPT-f 用预训练模型生成 tactic 序列,Lean 的检查器负责给每一步打分;LeanCopilot 直接在编辑器里给数学家提供自动补全和 auto 策略;还有用蒙特卡洛树搜索在 Lean 验证反馈下搜索证明树的系统。Mathlib 统一数学库则成了 AI 的「语料库」,模型可以从中模仿人类数学家积累的成千上万条证明模式。

对比 Coq 和 Isabelle:Coq 同样强大,但它的数学库不像 Mathlib 那样统一,学习曲线也更陡;Isabelle 的自动化工具链(如 sledgehammer)很出色,但它的脚本语言与目标语言分离。Lean 主张代码与证明一体化、内核小、元编程能力内置,因此被不少研究者当作「AI 原生」的定理证明平台。这种偏好已经形成气候——Leandojo 等基准测试都建立在 Lean 之上。

对 AI 来说,Lean 是一个规格统一、验收迅速的工地;对数学家来说,它又是一本能自动查错的工程手册。这双重身份,让 Lean 成为连接人类数学与机器推理的那座桥。

Goal0→t1Goal1→t2⋯→tn∙\displaystyle \mathrm{Goal}_0 \xrightarrow{t_1} \mathrm{Goal}_1 \xrightarrow{t_2} \cdots \xrightarrow{t_n} \bullet
这是 AI 在 Lean 中证明定理的抽象过程:初始目标经过一串 tactic 逐步收缩,最后到达空目标(●)。每一步都有检查器验收,所以 AI 可以放心大胆试错。
  1. 初始目标$\mathrm{Goal}_0$ 是桥刚开工时的待铺桥段,比如「证明 P→P」。
    Goal0\mathrm{Goal}_0
  2. 战术箭头$t_1, t_2, \dots, t_n$ 是 AI 选出的 tactic,每个箭头让目标前进一跨,像起重机吊过一段梁。
    →t1\xrightarrow{t_1}
  3. 空目标$\bullet$ 表示目标列表清空,证明通过,桥已通车——这就是 AI 模型要学习的「满分动作」。
    ∙\bullet

AI 应用场景

Mathlib 数学知识众包

阶段:数据构建与知识表示

解决的问题:传统数学知识存在于论文和教科书中,格式不统一、难以被机器利用,就像各家造的桥板规格五花八门,机器人没法上手。Lean 社区通过 Mathlib 把大量定理形式化为统一标准的知识库,让 AI 能批量学习「标准桥板」的搭法。

具体案例:Lean 社区像开源软件一样协作,顶尖数学家与爱好者一起把代数、分析、拓扑等领域定理逐一形式化。AI 模型在 Mathlib 上训练后,能自动补全证明片段,形成「人机协作造桥」生态。

关键代码与智能合约验证

阶段:模型推理与安全验证

解决的问题:智能合约漏洞动辄造成上亿美元损失,传统测试只能证明「测过的场景没问题」,无法证明「所有场景都没问题」。用 Lean 把合约规格写成定理并证明,相当于给这座金融之桥做全桥无损检测。

具体案例:区块链团队用 Lean 形式化验证借贷协议的核心函数,证明「任何存款操作后,用户资产余额不小于理论值」,从数学上排除溢出和重入漏洞。

AI 证明助手的训练环境

阶段:强化学习与自动定理证明

解决的问题:通用大模型做数学推理时,常出现「看起来合理但实际错误」的幻觉,原因是缺少可靠的即时反馈。Lean 的每次 tactic 执行都能给出确定性的成功/失败信号,像一个绝不会放水的监理。

具体案例:研究者用 Lean 的证明环境训练策略网络,让模型在目标状态下选择下一个 tactic;配合 Mathlib 语料做预训练,AI 在高中数学竞赛题和部分大学数学习题上的证明通过率大幅提升。

Python 演示

python75 行
# -*- coding: utf-8 -*-"""迷你 Lean 证明引擎:用 intro 与 exact 两个 tactic 搭一座逻辑桥""" class Formula:    """一个朴素的逻辑公式:atom / arrow / conj"""     def __init__(self, kind, left=None, right=None, name=""):        self.kind = kind   # atom 原子, arrow 蕴含, conj 合取        self.left = left        self.right = right        self.name = name     def show(self):        if self.kind == "atom":            return self.name        if self.kind == "arrow":            return "(%s -> %s)" % (self.left.show(), self.right.show())        return "(%s /\\ %s)" % (self.left.show(), self.right.show())  def atom(name):    return Formula("atom", name=name)  P = atom("P")Q = atom("Q") # 目标:P -> Q -> P (对应 Lean 中 theorem tP : P -> Q -> P)TARGET = Formula("arrow", P, Formula("arrow", Q, P))  class State:    """证明状态:已知前提 + 当前目标"""     def __init__(self):        self.hyps = []   # [(名字, 公式)]        self.target = TARGET  def do_intro(st, steps, name):    """tactic intro:目标 A->B 时,把 A 收入前提,目标收窄为 B"""    t = st.target    if t.kind != "arrow":        return False    st.hyps.append((name, t.left))    st.target = t.right    steps.append("intro " + name)    return True  def do_exact(st, steps, name):    """tactic exact:前提中找到与目标相同的公式则收工"""    for (nm, f) in st.hyps:        if nm == name and f.show() == st.target.show():            steps.append("exact " + name)            st.target = None            return True    return False  def prove():    st = State()    steps = []    ok = do_intro(st, steps, "hP")    ok = do_intro(st, steps, "hQ") and ok    ok = do_exact(st, steps, "hP") and ok    return steps, ok  if __name__ == "__main__":    steps, ok = prove()    print("证明过程(与 Lean 的 tactic 一一对应):")    for s in steps:        print("  " + s)    print("证明结果:", "桥已连通,目标清空!" if ok else "目标未完成")
目的:用 Python 模拟 Lean 的最小证明引擎,展示 intro 与 exact 两个战术如何把命题 P → Q → P 一步步铺成一座逻辑桥。
  1. class Formula把逻辑公式建模成树,kind 标记原子命题、蕴含、合取,对应 Lean 中的类型构造器。
  2. st.hyps.append((name, t.left))把箭头左侧的前提收入上下文,这正是 Lean 中 intro 的语义:目标从 A→B 收窄成 B。
  3. if nm == name and f.show() == st.target.show()exact 要求前提名与目标完全一致,像监理核对桥板编号与图纸编号完全对应。
  4. ok = do_intro(...) and ok从后往前组装战术序列,保证每一步都成功后才算通过验收。
  5. prove()完整证明流程:两次 intro 收下 hP、hQ,最后 exact hP 命中目标,桥板铺完。

常见误区

误区以为跟 Lean 交流就像跟人解释数学题,把推理思路写成自然语言段落丢进去,机器就能「听懂」并返回通过。

正解Lean 只接受精确的形式化对象。证明是构造出来的类型项,不是描述性文字。就像监理不看「这板承重没问题」的书面保证,而要看实测数据曲线。你必须把每一步都转成 intro、apply、exact 这类精确操作,机器才会验收。

为何常见:人机交互的「指令感」让初学者误以为 Lean 具备自然语言理解能力,把证明过程与「给老师讲题」混淆了。

误区以为在 `by` 后面随便写几个高级 tactic(如 `simp`、`omega`),就能让所有目标自动消失,自己不用动脑。

正解每个 tactic 都是有限逻辑规则的封装:simp 只能做化简,omega 只解线性整数算术。超出能力范围,目标纹丝不动——就像起重机吊不起超过额定载荷的构件。真正有效的证明,仍然需要你选择正确的战术序列。

为何常见:看 Demo 时「一键通关」的印象太深,忽略了演示者事先精心挑选了适用场景。

误区默认所有定理证明器都是「证明过一遍」,无非界面不同,不必区分。

正解逻辑内核、社区生态、元编程能力、数学库风格的差异很大。Lean 主张代码即证明、Mathlib 统一库、内核精简;Coq 历史更久、学习曲线更陡、但也在自动化和库建设上不断进步。选型会影响整个工程流程,尤其在 AI 训练和数学库共建时差异会放大。

为何常见:初学者对 ITP 家族缺乏整体了解,把「定理证明器」当成一个无差别的工具类别。

误区以为 Lean/Coq 只是数学家的小众玩具,和软件工程、AI 系统毫无关系。

正解Lean 已被用于程序验证、智能合约审计、编译优化、协议安全性证明等场景。因为 Curry-Howard 对应让「代码」和「证明」是一回事,验证一段程序等价于证明它的类型正确——造桥的监理方法,同样能检验程序这座桥。

为何常见:被「定理证明器」这个名字误导,忽略了它本质上是「证明即程序」的平台。

误区以为 `inductive` 只是给一组固定值排队命名,像编程里的 enum。

正解归纳类型通过构造子递归生成,能表达无限结构,还能携带命题依赖(依值归纳)。自然数、列表、树、甚至「相等关系」的证明都靠它定义。枚举只是归纳类型的一个退化特例——没有递归参数的归纳类型。

为何常见:编程语言里的 enum 先入为主,让人低估了「有限构造、无限生成」这个设计的威力。

面试题

Q1. Lean 定理证明器的逻辑基础是什么?

单选题 · easy

  • A.朴素集合论
  • B.依值类型论← 正确答案
  • C.经典布尔代数
  • D.抽象范畴理论

答案:B。Lean 建立在依值类型论之上,命题是类型、证明是项,这套体系也叫 Curry-Howard 对应。集合论虽然能表达数学,但不是 Lean 的内核;布尔代数太简单,范畴论则是更抽象的结构,也不是内核。选 B。

Q2. 在 Lean 中,一个命题 P 本身是一个什么?

单选题 · easy

  • A.一个字符串
  • B.一个类型,其证明是一个项← 正确答案
  • C.一个数据库记录
  • D.一个语法关键字

答案:B。命题即类型:命题 P 是一个类型,P 的证明是这种类型的一个项。就像「桥板规格书」是一个文档类别,「合格的桥板」是符合该规格的具体对象。字符串、数据库记录、语法关键字都不是命题的本质。选 B。

Q3. 面对形如 P → Q 的目标,最直接的第一步战术是哪个?

单选题 · easy

  • A.exact h
  • B.rfl
  • C.intro h← 正确答案
  • D.revert h

答案:C。intro h 把箭头前的 P 收进前提,目标变成 Q,对应 lambda 抽象。exact 需要已有项与目标完全一致;rfl 只管自反相等;revert 是 intro 的反向操作。所以面对蕴含目标第一步常用 intro。选 C。

Q4. rfl 战术专门处理哪种形式的目标?

单选题 · mid

  • A.x 等于 x 的自反式← 正确答案
  • B.P 且 Q 的合取式
  • C.P 或 Q 的析取式
  • D.任意全称命题式

答案:A。rfl(reflexivity)处理自反相等,即 x = x 这一秒通形式,像监理一眼看出「这板跟图纸就是同一块」。合取需要 constructor,析取需要 left/right,全称需要 intro。选 A。

Q5. 在 Lean 中 inductive Nat 定义了零和哪个构造子?

单选题 · mid

  • A.succ 后继构造子← 正确答案
  • B.add 加法函数
  • C.sub 减法函数
  • D.mul 乘法函数

答案:A。inductive Nat | zero | succ (n : Nat) 只有两个构造子:zero 和 succ。加、减、乘是用递归定义的函数,不是构造子。零是桥台,succ 是生产线,两者一起才生成全部自然数。选 A。

Q6. 数学归纳法对应 Lean 中归纳类型的哪个原理?

单选题 · mid

  • A.recursion 递归原理
  • B.induction 归纳原理← 正确答案
  • C.cases 分情况讨论
  • D.exact 精确项

答案:B。induction 原理对应「结构归纳法」,是证明 ∀ n, P n 的核心武器,由归纳类型自动生成。recursion 用于定义计算函数而不是证明命题;cases 只做分情况不加归纳假设;exact 是给出精确项。选 B。

Q7. 为什么定理证明社区常用 Lean 作为 AI 训练目标?

单选题 · hard

  • A.它支持 C++ 插件
  • B.库内满载训练语料
  • C.每步都可机器验证← 正确答案
  • D.完全不需人工标注

答案:C。AI 训练需要稠密可靠的反馈信号,Lean 每一步 tactic 都产生目标变化和验证结果,天然适合强化学习。支持 C++ 插件不是训练原因;库内有语料是结果而非原因;「完全不需人工标注」过于绝对。选 C。

Q8. Lean 中常用的基本 tactic 包括哪些?

多选题 · mid

  • A.intro← 正确答案
  • B.apply← 正确答案
  • C.exact← 正确答案
  • D.vector

答案:ABC。intro、apply、exact 是 Lean 最基础的三个战术,分别对应蕴含引入、反向规则应用和精确匹配。vector 不是战术,而是 Coq/Lean 里的一种归纳数据类型(定长列表)。选 A、B、C。

Q9. 下列属于 Lean 相比 Coq 社区优势的有哪些?

多选题 · hard

  • A.Mathlib 统一数学库← 正确答案
  • B.代码与证明一体化← 正确答案
  • C.内核精简且可扩展← 正确答案
  • D.只能靠 Python 扩展

答案:ABC。Mathlib 是统一数学库,Lean 强调代码与证明一体化,内核小且元编程能力强,这些都是社区常提的优势。但 Lean 的扩展主要通过自身语言完成,并非「只能靠 Python」。选 A、B、C。

Q10. 依值类型论中的宇宙层级 Type : Type 1 解决什么问题?

单选题 · extreme

  • A.避免类型包含自身的悖论← 正确答案
  • B.让类型可以无限递归
  • C.允许任意类型相等
  • D.使证明变为不可判定

答案:A。Type : Type 1 通过宇宙分层避免「所有类型都包含自身」导致的罗素式悖论,就像规范书的归档层级必须比规范书本身高一级。类型的递归由归纳类型负责;类型相等需要额外公理;证明不可判定性是另一回事。选 A。