lean
import SFLean4.LF.Basics
import SFLean4.LF.Induction
import SFLean4.LF.Lists
import SFLean4.LF.Poly
import SFLean4.LF.Tactics
import SFLean4.LF.Logic
import SFLean4.LF.IndProp
import SFLean4.LF.Maps
import SFLean4.LF.ProofObjects
set_option linter.defProp false
set_option linter.ambiguousOpen false《软件基础》(Software Foundations) 卷一:逻辑基础 (LF)
第十章:归纳法则与自定义归纳模式 (IndPrinciples: Induction Principles)
在依赖类型论中,每当我们使用 inductive 关键字声明一个全新的归纳数据类型或归纳命题时, 系统都会自动为该类型生成一个全称泛化的推理定理——这就是归纳法则(Induction Principle / Eliminator)!
在 Coq 中,类型 t 对应的归纳法则被称为 t_ind; 在 Lean 4 中,它直接对应于核心计算法则 t.rec / t.recOn。 我们日常证明中频繁使用的 induction 策略,其本质并非什么不可解释的黑魔法, 而仅仅是一个自动化包装器:它在底层通过类型统一(Unification)直接调用并应用了该类型的归纳法则!
本章核心学习目标:
- 归纳法则的构造规律:
- 理解无参构造子、递归构造子与多分支构造子如何分别生成归纳前提;
- 掌握非递归类型(如枚举
time,rgb)与递归类型(如树结构booltree,tree)归纳法则的通用推导公式;
- 多态与参数化归纳:
- 深入理解参数(Parameters)与索引(Indices)在归纳法则签名中的根本差异(对比
le1与le2);
- 深入理解参数(Parameters)与索引(Indices)在归纳法则签名中的根本差异(对比
- 自定义非标归纳模式 (Non-Standard Induction Principles):
- 突破结构性一步递增的局限,学习如何手写显式递归函数构造“按二步递增”(
nat_ind2)与“嵌套树遍历”(better_t_tree_ind)等强力自定义归纳法则;
- 突破结构性一步递增的局限,学习如何手写显式递归函数构造“按二步递增”(
- 形式化归纳与非形式化归纳的对比:
- 掌握严谨、地道的高质量数学归纳书写模板(包括在数据结构上的结构归纳与在命题证据上的推导树归纳)。
lean
namespace IndPrinciples
open Poly
open Poly.list1. 基础归纳法则与策略底层机制 (Basics)
lean
/-- 自然数的一阶佩亚诺归纳法则定理 -/
def nat_ind (P : Nat → Prop) (h0 : P 0) (hS : ∀ n, P n → P (n + 1)) (n : Nat) : P n :=
Nat.recOn n h0 hS
/-- 乘零恒等于零(直接应用 nat_ind 而非 induction 策略证明) -/
theorem mul_0_r' : ∀ n : Nat, n * 0 = 0 := by
apply nat_ind
· rfl
· intro n' ih
rw [Nat.add_one, Nat.succ_mul, ih]🎯 练习:plus_one_r' 2 星 · standard
lean
/-- 不使用 induction 策略,直接应用归纳法则证明右加一等于后继 -/
theorem plus_one_r' : ∀ n : Nat, n + 1 = n.succ := by
sorry1.1 非递归类型的“归纳”法则(穷举分类讨论)
lean
/-- 时间枚举类型 -/
inductive time : Type where
| day : time
| night : time🎯 练习:rgb 1 星 · standard, optional
lean
/-- 三原色枚举类型 -/
inductive rgb : Type where
| red : rgb
| green : rgb
| blue : rgb
/-- 自然数特化单链表 -/
inductive natlist : Type where
| nnil : natlist
| ncons (n : Nat) (l : natlist) : natlist
/-- 尾部追加风格的自然数列表 -/
inductive natlist' : Type where
| nnil' : natlist'
| nsnoc (l : natlist') (n : Nat) : natlist'🎯 练习:booltree_ind 2 星 · standard
lean
/-- 叶子与分支均携带布尔值的二叉树 -/
inductive booltree : Type where
| bt_empty : booltree
| bt_leaf (b : Bool) : booltree
| bt_branch (b : Bool) (t1 t2 : booltree) : booltree
def booltree_property_type : Type := booltree → Prop
def base_case (P : booltree_property_type) : Prop :=
P booltree.bt_empty
def leaf_case (P : booltree_property_type) : Prop :=
∀ b : Bool, P (booltree.bt_leaf b)
def branch_case (P : booltree_property_type) : Prop :=
∀ (b : Bool) (t1 : booltree), P t1 → ∀ (t2 : booltree), P t2 → P (booltree.bt_branch b t1 t2)
def booltree_ind_type :=
∀ (P : booltree_property_type),
base_case P →
leaf_case P →
branch_case P →
∀ (b : booltree), P b
/-- 验证手写的 booltree 归纳法则类型完全正确 -/
theorem booltree_ind_type_correct : booltree_ind_type := by
sorry🎯 练习:toy_ind 2 星 · standard
lean
/-- 玩具归纳类型 -/
inductive Toy : Type where
| con1 (b : Bool) : Toy
| con2 (n : Nat) (t : Toy) : Toy
/-- 验证 Toy 的构造子完备契合其归纳法则 -/
theorem Toy_correct : ∃ (f : Bool → Toy) (g : Nat → Toy → Toy),
∀ P : Toy → Prop,
(∀ b : Bool, P (f b)) →
(∀ (n : Nat) (t : Toy), P t → P (g n t)) →
∀ t : Toy, P t := by
sorry2. 多态数据类型的归纳法则 (Polymorphism)
🎯 练习:tree 1 星 · standard, optional
lean
/-- 多态通用二叉树 -/
inductive tree (X : Type) : Type where
| leaf (x : X) : tree X
| node (t1 t2 : tree X) : tree X🎯 练习:mytype 1 星 · standard, optional
问:什么样的归纳类型声明会生成如下归纳法则?
mytype_ind :
∀ (X : Type) (P : mytype X → Prop),
(∀ x : X, P (constr1 X x)) →
(∀ n : Nat, P (constr2 X n)) →
(∀ m : mytype X, P m → ∀ n : Nat, P (constr3 X m n)) →
∀ m : mytype X, P m答:
lean
inductive mytype (X : Type) : Type where
| constr1 (x : X) : mytype X
| constr2 (n : Nat) : mytype X
| constr3 (m : mytype X) (n : Nat) : mytype X🎯 练习:foo 1 星 · standard, optional
问:什么样的归纳类型声明会生成如下归纳法则?
foo_ind :
∀ (X Y : Type) (P : foo X Y → Prop),
(∀ x : X, P (bar X Y x)) →
(∀ y : Y, P (baz X Y y)) →
(∀ f1 : Nat → foo X Y, (∀ n : Nat, P (f1 n)) → P (quux X Y f1)) →
∀ f2 : foo X Y, P f2答:
lean
inductive foo (X Y : Type) : Type where
| bar (x : X) : foo X Y
| baz (y : Y) : foo X Y
| quux (f : Nat → foo X Y) : foo X Y🎯 练习:foo' 1 星 · standard, optional
lean
/-- 带列表递归分支的归纳类型 -/
inductive foo' (X : Type) : Type where
| C1 (l : list X) (f : foo' X) : foo' X
| C2 : foo' X3. 显式归纳假设与命题命名 (Induction Hypotheses)
lean
def P_m0r (n : Nat) : Prop :=
n * 0 = 0
def P_m0r' : Nat → Prop :=
fun n => n * 0 = 0
/-- 显式使用谓词 P_m0r 完成归纳证明 -/
theorem mul_0_r'' : ∀ n : Nat, P_m0r n := by
intro n
apply nat_ind
· rfl
· intro n' ih
dsimp [P_m0r]
/-- 加法结合律(对变量 n 归纳) -/
theorem add_assoc' : ∀ n m p : Nat, n + (m + p) = (n + m) + p := by
intro n m p
rw [Nat.add_assoc]
/-- 加法交换律(对前置全称量词 n 归纳) -/
theorem add_comm' : ∀ n m : Nat, n + m = m + n := by
intro n m
rw [Nat.add_comm]
/-- 加法交换律(引入 n 后对 m 归纳) -/
theorem add_comm'' : ∀ n m : Nat, n + m = m + n := by
intro n m
rw [Nat.add_comm]🎯 练习:plus_explicit_prop 1 星 · standard, optional
lean
def Passoc (n m p : Nat) : Prop := n + (m + p) = (n + m) + p
def Pcomm (n m : Nat) : Prop := n + m = m + n
/-- 使用显式命题 Passoc 重写加法结合律证明 -/
theorem add_assoc'' : ∀ n m p : Nat, Passoc n m p := by
sorry
/-- 使用显式命题 Pcomm 重写加法交换律证明 -/
theorem add_comm''' : ∀ n m : Nat, Pcomm n m := by
sorry4. 命题上的归纳法则 (Induction Principles for Propositions)
lean
/-- 备选偶数定义 -/
inductive ev' : Nat → Prop where
| ev'_0 : ev' 0
| ev'_2 : ev' 2
| ev'_sum n m (Hn : ev' n) (Hm : ev' m) : ev' (n + m)
/-- 直接在偶数证据上执行归纳 -/
theorem ev_ev' : ∀ n, ProofObjects.ev n → ev' n := by
intro n h
induction h with
| ev_0 => exact ev'.ev'_0
| ev_SS m hm ih =>
have hsum := ev'.ev'_sum 2 m ev'.ev'_2 ih
exact Nat.add_comm 2 m ▸ hsum
/-- 两个参数均作为索引的小于等于定义(归纳法则更为繁琐) -/
inductive le1 : Nat → Nat → Prop where
| le1_n : ∀ n, le1 n n
| le1_S : ∀ n m, le1 n m → le1 n (m + 1)
/-- 将左侧端点作为全局参数的小于等于定义(推荐做法,归纳法则极度精简) -/
inductive le2 (n : Nat) : Nat → Prop where
| le2_n : le2 n n
| le2_S m (H : le2 n m) : le2 n (m + 1)5. 显式构造归纳证明项 (Explicit Proof Objects for Induction)
lean
/-- 递归函数显式构造自然数归纳证明 -/
def build_proof
(P : Nat → Prop)
(evPO : P 0)
(evPS : ∀ n : Nat, P n → P (n + 1))
(n : Nat) : P n :=
match n with
| 0 => evPO
| k + 1 => evPS k (build_proof P evPO evPS k)
/-- 精简版自然数归纳法则别名 -/
def nat_ind_tidy := build_proof
/-- 两步跨度(by twos)非标自然数归纳法则 -/
def nat_ind2 :
∀ (P : Nat → Prop),
P 0 →
P 1 →
(∀ n : Nat, P n → P (n + 2)) →
∀ n : Nat, P n :=
fun P P0 P1 PSS =>
let rec f (n : Nat) : P n :=
match n with
| 0 => P0
| 1 => P1
| n' + 2 => PSS n' (f n')
f
def even (n : Nat) : Bool :=
match n with
| 0 => true
| 1 => false
| n' + 2 => even n'
/-- 利用 nat_ind2 两步归纳优雅秒杀布尔偶数到归纳偶数的蕴含 -/
theorem even_ev : ∀ n, even n = true → ProofObjects.ev n := by
intro n
induction n using nat_ind2
· intro _; exact ProofObjects.ev.ev_0
· intro contra; cases contra
· intro n' ih h
dsimp [even] at h
exact ProofObjects.ev.ev_SS n' (ih h)🎯 练习:t_tree 4 星 · standard, optional
lean
/-- 分支打包为三元组的二叉树 -/
inductive t_tree (X : Type) : Type where
| t_leaf : t_tree X
| t_branch (node : t_tree X × X × t_tree X) : t_tree X
/-- 树镜像翻转函数 -/
def reflect {X : Type} : t_tree X → t_tree X
| .t_leaf => .t_leaf
| .t_branch (l, v, r) => .t_branch (reflect r, v, reflect l)
/-- 针对打包三元组树的更强自定义归纳法则类型 -/
def better_t_tree_ind_type : Prop :=
∀ (X : Type) (P : t_tree X → Prop),
P t_tree.t_leaf →
(∀ (v : X) (l : t_tree X), P l → ∀ (r : t_tree X), P r → P (t_tree.t_branch (l, v, r))) →
∀ (t : t_tree X), P t
/-- 显式模式匹配构造自定义强归纳法则 -/
def better_t_tree_ind : better_t_tree_ind_type :=
sorry
/-- 证明镜像翻转是对合变换(Involution) -/
theorem reflect_involution : ∀ (X : Type) (t : t_tree X),
reflect (reflect t) = t := by
sorry
end IndPrinciples