3 初始模块
3.1 预定义句法
- Lean 启动时自动导入库中
Init模块的内容 -
定义范畴如下
3.1.1 项范畴
-
条件表达式
-
termIfThenElse:通用if表达式 -
termIfLet:可使用模式匹配,在某些场景下能代替match -
termDepIfThenElse:绑定一个证据变量,在then分支提供命题的证明,在else分支提供命题的证伪
-
-
计算式:定义
Trans类型类实例后可以配置为任意形式的关系式 -
管道符:用
f $ x、f <| x或x |> f表示f x,用f $ g $ x或f <| g <| x表示f (g x) -
字符串插值:组合子
interpolatedStr解析含有{term}的字符串,将其解释为项(而非字符串)
3.1.2 句法范畴
-
内置解析器
Lean/Parser/Tactic.lean Lean/Parser/Do.lean -
层级相关宏
-
优先级相关宏
-
组合子运算符
3.1.3 策略范畴
-
改变证明目标
-
apply:整合结论与当前目标中的表达式,并为剩余的未证明部分创建新目标apply_rfl:应用形如x ~ x的目标,其中~是不为等词的自反关系constructor:总是应用递归定义类型的第一个适用构造子
-
exact:当目标类型与提供的表达式类型相同时,关闭主要目标refine e与exact e类似,但refine e在当e中空洞(?x或?_)未解决时转化为新目标admit:相当于exact sorry
-
intro:引入任何类型的变量intro e引入匿名假设,可使用单项模式匹配intro | n + 1, 0 => tac | ...:多项模式匹配
-
revert:将假设(以及上下文中所有依赖它的后续元素)还原到目标,产生一个蕴含;相当于intro的逆操作 -
generalize:将目标中的任意表达式替换为新的变量generalize ([h :] e = x),+将所有出现的e替换为x,若h被指定,则h : e = x也被引入generalize e = x at h₁ ... hₙ:在h₁, ...,hₙ内泛化egeneralize e = x at *:泛化所有e
-
-
证明结构化
-
case:子目标分支case tag => tac:基本形式case tag x₁ ... xₙ => tac:重命名若干个最新假设并使名称可见case tag₁ | tag₂ => tac:相当于(case tag₁ => tac); (case tag₂ => tac)
-
cases:分解归纳类型,当接续表达式(cases e)时 相当于generalize e = n; cases ncases h with | cons₁ => tac₁ | cons₂ => tac₂:类似于模式匹配cases h:非结构化组织,也可用case结构化
-
induction:归纳证明- 结构与
cases类似,可使用with或case induction接受归纳前提作为参数,且只能接续标识符using可接受自定义递归器作为归纳原则
- 结构与
-
split:分割嵌套的if或match结构 -
cdot:匿名分支目标,可用于case或cases
-
-
启发式自动化
-
rfl:相当于exact rfl -
rewrite或rw:依次利用一系列类型断定为等式的项对目标进行重写,并在得到形如t = t的恒等式后自动关闭证明- 重写策略在遍历项时选择发现的第一个匹配,可通过附加参数指定适当的子项
←t指示策略在反方向上使用等式t
-
simp:反复重写目标项,以任意顺序在任何适用位置重复应用等式simp策略使用局部列表与所有带有simp属性的定理重写simp only排除使用默认值,仅使用列表内的定理简化- 可在列表内使用通配符
*以使用局部环境中存在的所有假设,或用-前缀阻止使用特定定理
-
assumption:在当前目标的背景下查看假设,若有与结论相匹配的假设,则应用此假设 -
contradiction:搜索当前目标假设中的矛盾 -
injection:若c是归纳类型的构造子,则(c m₁ n₁) = (c m₂ n₂)蕴含m₁ = m₂与n₁ = n₂
-
-
组合器:与其他策略组合使用
-
try:尝试使用策略,不返回错误 -
repeat:多次使用某个策略repeat tac:多次使用策略tac直到失败,因此该策略必须最终失败repeat' tac:多次递归使用策略tac直到失败,即如果生成子目标,也会使用tacrepeat1' tac:多次使用策略tac直到失败,必须至少成功一次
-
tac <;> tac':在主要目标上运行tac,并对产生的每个子目标使用tac' -
first | tac | ...:运行每个策略直到其中一个成功,否则返回失败 -
all_goals与any_goals:将策略应用于所有未完成的目标,直到所有(或至少一个)目标成功 -
focus:确保策略只影响当前的目标,暂时将其他目标从作用范围中隐藏 -
unhygienic:允许访问 Lean 自动生成的名称
-
-
表达式策略
3.1.4 do 元素范畴
-
repeat:循环 -
while:等效于repeat与 带有if修饰的break
3.2 预定义函数
3.2.1 递归器
-
rec:消去递归器motive是被定义函数的陪域,归纳分支是小前提,类型元素是大前提recOn:基于rec实现,大前提发生在小前提之前brecOn:基于rec与below实现binductionOn:基于rec与ibelow实现,第二归纳法
-
casesOn:基于rec实现,分支递归器- 模式匹配基于
casesOn实现 casesOn相当于小前提中没有motive作为条件的recOn
- 模式匹配基于
-
below:基于rec实现,仅用于递归类型(不用于枚举类型与结构类型)- 若
e : T,则@T.below motive e是含有所有结构上「小于」e的、存储motive e的数据 ibelow:基于rec实现,motive e类型仅为Prop
- 若
-
noConfusion:基于casesOn实现,仅用于归纳类型,用以区分同一类型下使用不同构造子的元素
3.2.2 函数
-
函数相关
-
id:恒等函数 -
Function.comp:复合函数 -
Function.const:常函数 -
inferInstance:提供一个类型实例,可以(inferInstance : T)的形式使用
-
-
参数标记
-
optParam:标记可选参数,x : optParam α default相当于(x : α := default) -
outParam:在类型类中标记输出参数,在无法进行实例搜索时运行类型类推断,并采用找到的第一个解决方案 -
semiOutParam:在类型类中标记半输出参数,此时类型类的实例需始终为该参数填充一个值
-
3.3 内建类型
3.3.1 结构体类型
-
数据类型
-
Prod:直积类型 -
Fin:严格小于n的自然数,UInt系列类型在运行时用固定精度的机器整数表示 -
Float:浮点数 -
Char:字符,运行时以用一般字符表示
-
-
数据结构
-
Array:数组,此类型在运行时有特殊处理- 数组在以线性方式使用,且所有更新都将对数组进行破坏性执行时性能最佳
- 从证明观点来看,
Array α仅是List α的包装类
-
String:字符串,编译器会将此类型的数据表示覆盖为 UTF-8 编码的字节序列 -
Subtype:子类型,包括值val与证据property
-
3.3.2 归纳类型
-
枚举类型
-
Sum:和类型 -
Empty空类型,没有构造子 -
Unit:单位类型,具有一个元素的规范类型 -
Option:可选类型,用于表示失败的可能性或可空性 -
Bool:真值类 -
Exception:异常类
-
-
递归类型
-
Nat:自然数,内核与编译器都对此类型进行了特殊处理- 内核可将
zero或succ n表达式简化为自然数字面值 - 运行时本身具有
Nat的特殊表示(直接存储最多 63 位数字),更大的数字使用任意精度的bignum - 宏
nat_lit构建一个原始数字字面值,可以用于避免定义时的无穷倒退nat_lit对应表达式的Expr.lit (.natVal n)- 解析器将数字字面值转化为
(OfNat.ofNat (nat_lit n) : α),即使α为Nat
- 内核可将
-
Int:整数,当数字较小时直接存储有符号整数,较大的数字(超过 63 位时)使用任意精度bignum库 -
List:(有序)列表,以链表形式实现- 当尾部的多个值共享时,
List α更易用于持久数据结构,否则Array α的性能更好,因其可以进行破坏性更新 [a, b, c]是a :: b :: c :: []的简记,%[a, b, c | tail]是a :: b :: c :: tail的简记
- 当尾部的多个值共享时,
-
-
编译相关
-
Name:名称,由点.分隔的一系列字符串或数字anonymous:顶级名称,例如Lean.Meta表示为.str (.str .anonymous "Lean") "Meta"str:字符串名称num:数字名称,用于自由变量和元变量的层次名称
-
Syntax:句法结构,其中SyntaxNodeKind即节点类别,用于给Syntax元素分类missing:对应于由于解析错误而缺失的句法树部分node:类别为kind,子节点包含在args的节点atom:对应关键字或字面值ident:对应由ident或rawIdent解析的标识符
通常使用
TSyntax,即给定句法类别的Syntax- 范畴是对类别的再分组,但部分类别没有范畴
- 可使用
`()句法模式代替TSyntax或Syntax进行模式匹配
-
Expr:表达式.Lean 中任意项都有对应表达式bvar:约束变量,用 \(\text{de Bruijn}\) 序列表示fvar:自由变量,即非约束出现的变量,用LocalContext内的 ID 表示mvar:元变量,相当于表达式中的占位符,用MetavarContext内的 ID 表示sort:Sort u、Type u或PropProp表示为.sort .zero,Sort u表示为.sort (.param `u)Type u表示为.sort (.succ (.param `u))
const:在模块中或由另一个导入的模块先前定义的(多态)常量app:函数应用.使用部分应用来表示多个参数lam:\(\lambda\) 表达式lam n t b,相当于fun ($n : $t) => $bforallE:依值箭头表达式forallE n t b,相当于($n : $t) → $b
非依值箭头表达式α → β是依值箭头表达式(a : α) → β(其中β不依赖于a)的特殊情形letE:let表达式letE n t v b,相当于let ($n : $t) := $v in $blit:字面值.并非真实需要,仅为自然数或字符串在内存中提供更紧凑的表示mdata:元数据,提供位置信息、Syntax节点引用、对 Pretty Printer 的提示以及繁饰过程信息proj:投影,即扩展字段记号.并非真实需要,仅为项提供更紧凑的表示以加速归约
-
-
IO 活动:
EStateM同时跟踪状态和错误,是IO单子的基础- 状态即现实世界,由于机能限制而仅用
Unit表示 -
EStateM ε σ单子不改变状态,仅传递结果或错误信息
单子在求值前已经确定
-
对不与外界交互(即不引入 IO)的程序,所有单子行为固定
-
对与外界交互的程序,主函数
main归约结果是函数,只有#eval启动时,才能得到返回值(并执行副作用)- 内部视角:IO 活动没有副作用,它接受一个唯一的现实世界状态,返回改变后的世界
- 外部视角:副作用实质上靠 Lean RTS(运行时系统)执行原语而得以可能,Lean 本身仅对 IO 活动原语进行描述
main的内容在执行前就得以确定,因为main只是「如何改变世界,并获得返回值/错误类型」的说明书
- 状态即现实世界,由于机能限制而仅用
3.3.3 类型类
-
算术运算
-
Neg:取负 -
HAdd:异构加法 -
HSub:异构减法 -
HMul:异构乘法 -
HDiv:异构除法 -
HPow:异构乘方 -
HAppend:异构连接 -
HMod:异构取余 -
Dvd:同余
-
-
逻辑运算
-
Complement:按位取反 -
HAnd:异构按位与 -
HXor:异构按位或 -
HOr:异构按位非 -
HShiftLeft:异构左移 -
HShiftRight:异构右移
真值运算
-
cond:条件运算 -
and:与运算 -
or:或运算 -
not:非运算
-
-
比较运算
-
LE:小于等于 -
LT:小于 -
GE:大于等于 -
GT:大于
-
-
关系与性质
-
Trans:传递性,可用于计算式证明 -
Deciable:可判定性,等同于Bool及其证明,用于推断命题的计算策略,从而可在if中编写命题并执行Init模块定义了等式和比较符的基本运算以及命题连词等命题的可判定性,例如
-
-
函子与单子
-
通用类型类
-
Functor:函子 -
Applicative:应用函子 -
Monad:单子
函子与单子的规约
- 函子的规约
id <$> x等价于xmap (fun y => f (g y)) x等价于map f (map g x)
- 应用函子的规约
- 同一律:
pure id <*> v等价于v - 函数复合律:
pure (· ∘ ·) <*> u <*> v <*> w等价于u <*> (v <*> w) pure f <*> pure x等价于pure (f x)u <*> pure x等价于pure (fun f => f x) <*> u
- 同一律:
- 单子的规约
pure为bind的左单位元:bind (pure v) f等价于f vpure为bind的右单位元:bind v pure等价于v- 结合律:
bind (bind v f) g等价于bind v (fun x => bind (f x) g)
易证任意单子都是应用函子,任意应用函子都是函子
-
-
类型转换与强制类型转换
-
OfNat:将自然数字面值转换到其他类型例如
37 : α相当于(OfNat.ofNat (nat_lit 37) : α) -
ToString:将其他类型转换到字符串,用于字符串插值或IO等 -
Coe:强制类型转换- 链式强制转换:通过一系列较小的强制转换组成完整的强制转换;存在循环强制转换时,Lean 不会陷入无限循环
- 当且仅当推断类型与程序需要类型不匹配时,Lean 才会自动使用强制转换
-
当强制转换结果依赖于具体值时,使用依值强制类型转换
CoeDep -
当强制转换结果为分类或函数时,使用
CoeSort或CoeFun
-
-
派生标准类:编译器可自动构造部分类型类的良好实例
-
Repr:表示类,将某种类型的值转换为Format类型 -
BEq:真值相等 -
Ord:排序 -
Hashable:散列值 -
Inhabited:默认值,通常在超出值域时调用非空归纳类型类
非空类区别于
Inhabited在于Nonempty α是一个命题,这表明其不携带存在的元素,而只证明存在这种元素-
命题
Nonempty α等价于命题∃ x : α, True -
命题
∃ x : α, p x不等价于类型{x : α // p x}- 前者是命题,其元素通常不可约,Lean 对其仅进行类型检查
- 后者是类型,其元素需要被存储或计算
因此前者通过
match得到的存在性见证不可直接用于后者,需要选择公理的介入
-
-
3.3.4 转换器
-
OptionT:组合Option单子.为了正确选取Monad实例,需要定义mk函数对应的类型类是
Alternative -
ExceptT:组合Except单子.为了正确选取Monad实例,需要定义mk函数-
MonadExceptOf与MonadExcept:异常的抛出与处理 -
MonadFinally:异常的后处理
-
-
ReaderT:组合ρ类型的配置-
MonadReaderOf与MonadReader:从单子m读取状态ρ -
MonadWithReaderOf与MonadWithReader:以被f : ρ → ρ修改的上下文运行内部x : m α
-
-
StateT:组合σ类型的状态对应的类型类包括状态的读写
3.4 数学基础
3.4.1 逻辑学
-
命题:区分于
Bool或Empty-
True:真命题 -
False:假命题
-
-
逻辑联结词
-
Not:否定 -
And:合取And.intro:合取引入规则And.left:左合取消去规则And.right:右合取消去规则
-
Or:析取Or.inl或Or.intro_left:左析取引入规则Or.inr或Or.intro_right:右析取引入规则Or.elim:析取消去规则
-
Iff:逻辑等价
-
-
量词
-
全称量词:通过依值类型实现
-
Exists:存在量词,可以如Exists.elim内部所示直接以match或let消去量词
-
-
等词与等价
-
Eq:等词Eq.refl可用于证明恒等式:定义等价的项会被视为相同- \(\beta-\)归约:替换绑定变量从而应用参数
- \(\delta-\)归约:用定义值替换已定义常量的出现
- \(\iota-\)归约:(原始递归)归约以构造子为目标的递归器
- \(\zeta-\)归约:用定义值替换
let绑定变量
-
Eq.subst:若a = b且e : p a,则h ▸ e : p b
-
Equivalence:等价与广集
-
-
良基性与良基归纳
-
Acc:在序关系r ≺下,当不存在无穷下降序列... ≺ y₂ ≺ y₁ ≺ y₀ ≺ x时,称x可被访问 -
WellFounded:良基性,即类型内任意元素均可被访问Nat的默认良基关系实例是<
-
3.4.2 扩展公理
-
propext:命题外延性,即互相蕴含的两个命题实质相等 -
Quot.sound:任意α中元素a, b有r a b蕴含Quot.mk r a = Quot.mk r b- 设
r'有r a b当且仅当Quot.mk r a = Quot.mk r br'为等价关系,且r a b蕴含r' a b- 若
r''是包含r的任意等价关系,则r' a b蕴含r'' a b
-
对于类型
α上的等价关系r,@Quot α r是商集,且Quot.mk r a = Quot.mk r b蕴含a ≈ b -
funext:函数外延性,通过Quot.sound公理证明
- 设
-
Classical.choice:选择公理-
indefiniteDescriptio:选择公理等价于非限定摹状词 -
Classical.em:排中律.根据 \(\text{Diaconescu}\) 定理,em可由propext、funext与Classical.choice导出 -
propDecidable:经典逻辑下所有命题都可判定
-