第一次看到“用编译器验证数学证明”这个说法时,你可能会觉得有点奇怪:数学证明不是拿笔在草稿纸上推的么,怎么扯到编译器和AI了?我之前也这么想,直到真的上手了 Lean 这个交互式定理证明器,才发现它的核心思路非常硬核:你把定理当成函数签名写下来,把证明过程当成程序一样逐步构建,Lean 的编译器内核会在后台把所有证明步骤编译成一个底层证明项,再逐条检查是否真的能推出结论。如果哪一步写错了,它立刻给你报错,根本不给含糊其辞的机会。
这个教程写给谁?写给想真正入门 Lean、同时也想知道 AI 到底怎么在数学证明里打辅助的初学者。我会从最基础的环境搭建开始讲,一路讲到第一个完整证明、Lean 怎么拆分数学推导过程,再教你怎么用 AI 来帮你写策略、解释报错、加快调试验证。全程每段代码都可以直接复制运行,你只要能装好环境,跟着敲一遍,基本就能明白“编译器验证数学证明”这件事到底是怎么转起来的。
1. 为什么数学证明需要“编译器”
1.1 笔算证明为什么靠不住
别误会,我不是说手写证明没有价值。数学系训练的就是那种“从公理出发,一步一步推到结论”的能力,这个思维过程永远重要。但问题是,一旦证明变长、变量变多、定义层叠套娃,人脑靠短时记忆去跟踪几十层子目标,出错率会急剧上升。
举个大家可能听过的例子:四色定理当年就是用计算机辅助验证的,数学家花了大量精力去核对程序,起初很多人都担心“这玩意儿到底算不算严格证明”。后来像 Kepler 猜想这种巨型证明,人工审稿甚至花了十几年。问题的本质说白了就一句话:人工检查是建立在“大家都认为这一步显然成立”之上的,而这个“显然”在某些上下文里是会骗人的。
LeaN 做的事情不是替代你思考,而是强制你把每一步“显然”变成编译器能接受的精确规则。你写下一步的时候,它不会因为你自认为“显然”就放你过去,而是要用它的逻辑内核把当前目标和已有假设做一次严格的模式匹配。这种做法和写代码时编译器强制做类型检查其实是一模一样的。
1.2 Lean如何把证明“翻译”给编译器
Lean 背后的核心思想叫“命题即类型”(Curry-Howard Correspondence)。这个概念听起来很吓人,其实说白了就一句话:一个数学命题可以看成一个类型,而“这个命题的一个证明”可以看成一个满足该类型的程序对象。
- 命题
a = b是一个类型; - 证明
a = b就是构造出一个类型为a = b的证明项; - 编译器内核负责检查这个证明项的类型是否真的等于命题对应的类型。
所以你在 Lean 里看到的所有 theorem、lemma、example,底层最后都会被归约成一个验证项。Lean 的“编译器”角色就在这里:它的内核只认最终生成的证明项,至于你是用 simp 一键搞定、还是用 induction 一步步推,它并不关心,它只关心最后交给它的证明项类型是否合法。
我自己觉得最容易理解的方式,是把 Lean 想象成一个特别较真的判卷老师。你把试卷交上去,老师不看你中间写得多花哨,只看你的每一条推论是否都符合已经被接受的规则。如果某个中间步骤用了“显而易见得证”,老师立刻打个红叉,告诉你这一步没有规则依据。
1.3 编译器与编辑器的区别
很多人刚接触 Lean 时会有一个误解:看到 VS Code 里飘红报错,以为是“编辑器”在报错。其实不是。编辑器只是负责给你展示文本、提供高亮和快捷键,真正干活的是一套独立的 Lean 后台服务。
- 编辑器:VS Code、Neovim、Emacs 都行,负责让你舒服地写代码,它本身不判断逻辑;
- 编译器/内核:Lean 的服务端负责解析代码、展开定义、检查类型、生成信息视图(Infoview)里那些目标状态和报错信息。
打个比方:编辑器是你的 Word,编译器是你的语法检查引擎。Word 本身不保证你写出来的句子是符合语法、符合逻辑的,它只是把错误标记出来的媒介。Lean 的内核才是那个真正会思考“你的证明能不能拼起来”的东西。
理解这个区别之后,你在排错时就不会再一头雾水:看到错误优先看内核给的提示,而不是怀疑电脑出了问题。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 零基础搭建Lean开发环境(含AI辅助准备)
2.1 在线版:五分钟跑通第一个证明
如果你只是想先体验一下 Lean 到底长什么样,最快的方式是用官方提供的在线编辑器,不需要安装任何东西。打开 Lean 的在线 playground,左侧是编辑区,右侧默认会显示当前文件的所有声明、目标状态和提示信息。
在编辑区输入下面这段代码,然后观察右侧:
lean复制example : 1 + 1 = 2 := by
rfl
只要右侧出现类似“No goals”的信息,就说明这个证明通过了。rfl 的意思是“左右两边在定义上就是相等的”,1 + 1 定义为 2,所以这一步可以直接结束。看起来很简单,但它已经包含了 Lean 最核心的工作流:你给出目标,编译器确认目标达成。
在线环境真正的价值在于,你不用先花半小时折腾安装环境,就能先跑起来看看“目标状态”长什么样。等你理解了 Lean 的工作方式,再考虑本地搭建环境写大项目也不迟。
2.2 本地版:VS Code + Lean4 完整安装
在线环境适合体验,但真要写证明、写策略、把项目做完整,还是建议本地装一套。本地环境的完整流程大概是下面这四步:
- 安装 Lean 的版本管理器
elan,它的作用类似 Rust 的rustup,负责管理 Lean 工具链版本; - 用
elan安装 Lean 工具链; - 在 VS Code 中安装 Lean4 扩展;
- 创建一个 Lean 项目,开始写代码。
如果你是在 macOS 或 Linux 上,打开终端执行:
bash复制curl -fsSL https://raw.githubusercontent.com/leanprover/elan/master/elan-init.sh | sh
source "$HOME/.elan/env"
lean --version
看到版本号后,说明 Lean 已经可用了。Windows 用户可以下载对应的安装器,或者在 Git Bash / WSL 里执行同样的脚本。装完后打开 VS Code,搜索扩展名 Lean4 并安装,重启编辑器,就能识别 .lean 文件了。
如果要跑需要 Mathlib 的大型项目,推荐用 lake 来创建项目模板。lake 是 Lean 自带的构建工具,类似 Python 的 pip 加 make。在终端执行:
bash复制lake new my_lean_test math
cd my_lean_test
lake update
lake build
code .
lake new ... math 会生成一个已经配置好 Mathlib 依赖的骨架项目,第一次构建通常会拉取并编译一批依赖,需要耐心等一会。等进度条走完,打开 Main.lean,就可以正常 import Mathlib 并使用全套数学定理库了。
提示:第一次构建 Mathlib 可能要好几分钟,这期间右下角会提示编译任务进度,不要反复关掉窗口或频繁按 Ctrl+Enter,耐心等它把缓存编完。
2.3 把“AI外挂”接进来
既然标题里提到 AI,那这一节直接说结论:AI 在你学 Lean 的过程中并不是替你思考,而是帮你查资料、帮你写策略片段、帮你解释报错。实际使用中,多数人都是在编辑器里写完代码,让 Lean 先报错,然后把报错信息复制给大模型,让 AI 帮忙分析“为什么类型不匹配”或“下一步该用什么策略”。
我自己常用的组合是:本地 VS Code 写证明 + 任意你用得顺手的通用大模型对话框。把 Lean 的目标状态贴给 AI,然后问它下一步该干嘛。这里有一个很关键的技巧:AI 生成的答案不一定正确,所以不要让 AI 直接给你一个“感觉没问题”的证明就完事,而是必须把它生成的代码复制回 Lean 里跑一遍,让编译器做最终裁决。
如果你希望更深度地结合 AI,可以试试 Lean Copilot 这类插件,它允许在 Lean 编辑器里直接调用大模型来生成 tactic 建议。安装和使用会有一些配置门槛,对于初学者来说,先用通用大模型 + 复制粘贴的方式已经完全够用。
3. 手把手拆解:Lean是怎么验证一个数学证明的
3.1 认识目标、策略和Infoview
在 Lean 里写证明,你看到的不是一个传统的文档,而是一个不断更新的“游戏面板”。这个面板就是 Infoview,它实时显示当前证明到了哪一步、现在需要证明的命题是什么、目前手上有哪些假设条件。
比如你在证明一个命题时,Infoview 可能显示:
text复制n m : ℕ
⊢ n + m = m + n
横线上面是当前上下文(上下文包括变量和已知假设),横线下面是要证明的目标。这时候你要做的每一件事,都叫 tactic(策略)。策略就是你发给 Lean 的命令,告诉它怎么把当前目标拆小、化简、套用已有定理。
你可以把目标状态想象成拆积木:目标是一块大积木,每个策略就是一把工具,把大积木拆成更小、更容易处理的积木,直到所有小积木都被清理干净,证明就完成了。Lean 的 Infoview 就是这个“积木进度条”,每一步都会清清楚楚告诉你还剩几块。
3.2 主案例:证明加法交换律
来看一个经典的新手案例:证明自然数的加法交换律,也就是 n + m = m + n。它需要用到数学归纳法,但代码很短,非常适合理解 Lean 怎么拆分数学推导过程。
在支持 Mathlib 的环境里运行以下代码:
lean复制import Mathlib
example (n m : ℕ) : n + m = m + n := by
induction n with
| zero =>
simp
| succ k ih =>
simp [Nat.add_succ, ih]
这段代码到底干了什么?初始目标就是要证明 n + m = m + n。induction n 把证明拆成两个子目标:
zero情况,即n = 0时,目标是0 + m = m + 0。这里simp会自动利用自然数加法的定义和已知定理,把两边化简成一样的表达式。succ k ih情况,即已经假设k + m = m + k(这个假设就是ih),要证明Nat.succ k + m = m + Nat.succ k。这时候用simp [Nat.add_succ, ih],它会把左右两边的加法展开,再用归纳假设ih替换需要替换的项,最后自动收尾。
你可能注意到,这里没有一步是“人工写展开过程”的,simp 自己就完成了大部分化简。这个策略有点像编译器里的“自动优化”,它会自动去找一组合适的重写规则,把目标两边变成同一个等式,直到两边明显相等。如果你把这条代码里的 simp 删掉,换成手动 rw,也能一步步写出来,但会很啰嗦。
这其实就回答了很多人问的“Lean 是怎么拆分数学推导过程的?”:它不是用魔法一步到位,而是把一个大证明拆成一串可以由编译器机械检查的小步骤。你告诉 Lean“这里用归纳法”、“那里用这个定理化简”,Lean 后台把所有策略编译成一个巨大的证明项,再由内核逐层检查。只要你每一步合法,整个证明就成立。
3.3 常用策略速查表
刚开始学策略,不需要硬背十几个,下面这些是最常用的“工具箱”,先把它们用熟就够了:
| 策略 | 作用 | 例子 |
|---|---|---|
intro |
消去普遍量词,把变量/假设放进上下文 | intro n m |
rfl |
两边在定义上相等,直接收尾 | rfl |
exact |
用已有的定理/假设直接证明目标 | exact Nat.mul_add a b c |
rw |
用等号定理重写目标 | rw [← Nat.add_assoc] |
simp |
自动化简大量表达式 | simp [Nat.add_succ, ih] |
induction |
数学归纳法 | induction n with ... |
rcases |
分解存在量词/合取式 | rcases h with ⟨k, hk⟩ |
refine |
用带洞的写法构造证明 | refine ⟨2 * k^2, ?_⟩ |
ring |
直接解多项式环恒等式 | ring |
omega |
解线性整数算术目标 | omega |
你现在不需要把每个策略的细节都背下来,只需要知道“看到目标时,大概有哪些工具可以用”。用多了自然就记住了。
4. AI怎么帮你写证明:实操示例
4.1 案例:用AI辅助证明“偶数平方仍是偶数”
光讲原理不够,来看一个更接近实际数学问题的例子:证明“如果 n 是偶数,那么 n^2 也是偶数”。这个命题在纸上写很方便,但用 Lean 来证明时,我们需要处理存在量词展开的问题。
先给 AI 一个提示词模板:
text复制我在学Lean4,请帮我证明下面这个命题:
import Mathlib
example (n : ℕ) (hn : ∃ k, n = 2 * k) : ∃ m, n^2 = 2 * m := by ...
请只输出Lean4代码,不要解释。
我实际使用中,AI 给出的证明骨架经常会类似这样:
lean复制import Mathlib
example (n : ℕ) (hn : ∃ k, n = 2 * k) : ∃ m, n^2 = 2 * m := by
rcases hn with ⟨k, rfl⟩
refine ⟨2 * k^2, ?_⟩
ring
这段代码的意思是:先把存在假设 ∃ k, n = 2*k 拆开,拿到具体的 k,再把它代进去。接着我们手动构造一个 m,猜它可能是 2 * k^2,最后用 ring 验证多项式恒等式。ring 是很强的策略,它会自动把括号展开、合并同类项,最后判定左右两边确实相等。
看出 AI 的作用了吗?它帮我做的其实是“找思路”:知道要 rcases 拆存在量词,知道要猜一个 m 的表达式,知道最后的代数化简交给 ring。而 Lean 里的 ring 会做最终验证,所以 AI 猜的 2 * k^2 就算差个符号,也会被编译器打回来要求从头再猜。
4.2 让AI解释错误信息
我在刚开始用 Lean 时,遇到最多的问题是“看不懂报错”。比如这种:
text复制type mismatch
a * 2
has type
ℕ
but expected
?m.1 * 2
面对这种错误,我经常的做法是把完整报错复制给 AI,然后加一句:“请指出这段 Lean4 代码中我搞错了什么,并给出修正后的代码。”AI 通常能很快指出问题所在,比如“自然数乘法没有直接用符号 · 表示”或者“你需要先引入某个库、先声明变量类型”。当然,AI 说的不一定对,但把它给的建议放回 Lean 里验证,很快就能收敛到正确写法。
这里我特别想强调一件事:AI 是生成器,Lean 是验证器,两者必须搭配使用。不要因为 AI 给了你一段看起来很像模像样的证明就直接贴进论文或项目,Lean 会非常诚实地用错误信息告诉你哪里有问题。这个“生成一堆候选证明、再由编译器筛选”的流程,其实和很多自动化证明研究项目里的思路是一致的。
4.3 在编辑器里用Lean Copilot(可选)
如果你不想频繁切到网页去问大模型,可以考虑安装 Lean Copilot 这类插件。它的作用是在你的编辑器里提供“生成下一个 tactic”或“找前提条件”的按钮,让你在写证明的过程中不用离开 VS Code。
安装方式一般是:先把 Lean Copilot 项目克隆到本地,在项目配置里加上对应依赖,然后在 Lean 代码里 import LeanCopilot。配置完成后,你可以在 tactic 位置使用它提供的命令,让模型根据当前目标推荐下一步操作。
不过说实话,对于初学者,我不建议一上来就折腾这类插件,因为配置本身就有一定学习成本。先把手动复制给 AI、再粘贴回 Lean 验证的流程跑熟了,你会对每一步策略背后的原理有更深刻的理解,再去用插件提升效率会顺畅很多。
5. 常见问题与排查技巧实录
5.1 报错信息到底在说什么
Lean 的报错风格非常直接,但刚开始你会觉得它像天书。下面我把最常见的几类错误整理成一个速查表,以后遇到红色波浪线,先对照一下:
| 报错关键词 | 含义 | 常用解法 |
|---|---|---|
unknown identifier |
你用了不存在的名字,通常是因为库没导入或拼写错误 | 确认是否 import Mathlib,检查大小写和拼写 |
type mismatch |
当前证明项的类型和目标不匹配 | 用 exact? 或询问 AI,检查方向是否正确 |
unexpected token |
语法解析失败,常见于括号不匹配或换行缩进错误 | 把小段代码单独跑,定位具体位置 |
sorry 警告 |
你用了“占位符”,编译器认为证明未完成 | 删除 sorry,补上真实证明 |
elaboration timeout |
目标太复杂、展开太深,导致超时 | 拆成多个小步骤,分步验证 |
sorry 是新手最容易误用的东西:它能让你暂时绕过这个目标,程序也能通过编译。但它就像编译器里的 TODO,如果最后忘了删,你的定理其实根本没有被证明。所以我的习惯是,写完一个证明后,搜索一下文件里有没有 sorry,确保全部清零再收工。
5.2 新手最容易踩的四个坑
第一个坑是拿到老教程里的 Lean3 代码直接复制。Lean3 和 Lean4 在语法和策略上有明显差异,很多 tactic 名字都变了。判断版本最简单的方式是看代码里用了 by 还是类似 by 后的语法,以及 import 的库名。如果你不确定,直接让 AI 帮你把代码转成 Lean4 版本。
第二个坑是本地环境没有正确配置 Mathlib。很多时候你写了 import Mathlib,但项目里并没有真正拉取依赖,于是大量 unknown identifier 冒出来。建议用 lake new xxx math 创建项目,而不是手动建空文件夹。
第三个坑是中文输入法输入特殊符号。Lean 里需要的数学符号可以通过反斜杠输入,比如 \to 得到 →,\a 得到 α,\nat 得到 ℕ。如果你直接在中文输入法下打这些字符,很容易打出全角符号,编译器会完全不认识。我自己就曾经在变量名里混进一个全角冒号,卡了二十分钟。
第四个坑是问 AI 问题时不给版本信息。如果你直接问“帮我写一段 Lean 证明”,AI 可能默认给你 Lean3 代码。正确的问法是“我用的 Lean4 + Mathlib4,请给出 Lean4 代码”,这样能减少大量返工。
5.3 如何让AI输出可编译的Lean代码(独家提示词)
最后分享一个我自己用得非常顺手的提示词框架。当你想让 AI 帮你写证明或排错时,至少提供三块信息:一段能跑的最小化代码、当前的目标状态或报错信息、以及明确的输出要求。
一个我常用的模板是:
text复制我有一段Lean4代码,当前目标如下:
(这里粘贴Infoview里的目标内容)
请只给出下一步tactic,不要解释原理,不要给完整证明。
这样做的原因是,AI 如果知道你要的是“下一步”,它就不会甩给你一篇完整证明,而是给你一个 rw [ih] 这样的短操作,你直接贴回 Lean 验证即可。如果这一步通过了,再继续问下一步;如果没过,把新报错再贴回去。这种“让 AI 当陪练、让 Lean 当裁判”的循环,是我目前发现的、对新学 Lean 的人最有效的一种节奏。
我个人在实际操作中最大的体会是,不要一上来就让 AI 替你写整个证明,然后幻想复制粘贴就能过。Lean 的编译器极其较真,AI 的“自信”在它面前毫无用处,任何一步不够精确都会被驳回。正确做法是把证明拆成很小的块,每块都拿给编译器试,通过了再拼起来。这个过程虽然看起来慢,但正因为内核每步都检查,你最后拿到的才是真正可靠、完整、没有漏洞的证明。等你用熟了就会发现,这种“AI 生成 + 编译器验证”的组合,比闭门造车手工核对舒服太多了。
