Lean 语言参考手册

10.5. 基础类🔗

Lean 中的许多类型类用于让加法、数组索引等内置记法可以重载。

10.5.1. 布尔相等性测试🔗

布尔相等运算符 == 通过定义 BEq 的实例来重载。 配套的 Hashable 类为类型指定哈希过程。 当某个类型同时具有 BEqHashable 实例时,计算出的哈希值应当遵循 BEq 实例:被 BEq.beq 判为相等的两个值应始终具有相同的哈希值。

🔗类型类
BEq.{u} (α : Type u) : Type u
BEq.{u} (α : Type u) : Type u

BEq α 是为 α 提供布尔值相等关系的类型类,记作 a == b。与使用 a = bDecidableEq α 不同,该关系取值于 Bool 而不是 Prop,也不要求满足 自反性或与 = 一致之类的公理。它主要用于编程。若需要保证 === 一致, 请参阅 LawfulBEq

通常应将“变化较多”的项放在左侧,将“较为固定”的项放在右侧。

BEq.mk.{u}
beq : α  α  Bool

布尔相等性测试,记作 a == b

🔗类型类
Hashable.{u} (α : Sort u) : Sort (max 1 u)
Hashable.{u} (α : Sort u) : Sort (max 1 u)

可哈希为 UInt64 的类型。

Hashable.mk.{u}
hash : α  UInt64

将一个值哈希为 UInt64

🔗不透明定义
mixHash (u₁ u₂ : UInt64) : UInt64
mixHash (u₁ u₂ : UInt64) : UInt64

一种不透明的哈希混合操作,用于实现积类型的哈希。

🔗类型类
LawfulBEq.{u} (α : Type u) [BEq α] : Prop
LawfulBEq.{u} (α : Type u) [BEq α] : Prop

布尔相等性测试与命题相等一致。

换言之:

  • a == b 蕴含 a = b

  • a == a 为真。

LawfulBEq.mk.{u}
rfl :  {a : α}, (a == a) = true

继承自父结构。

eq_of_beq :  {a b : α}, (a == b) = true  a = b

a == b 求值为 true,则 ab 在逻辑上相等。

🔗类型类
ReflBEq.{u_1} (α : Type u_1) [BEq α] : Prop
ReflBEq.{u_1} (α : Type u_1) [BEq α] : Prop

ReflBEq α 表示 BEq 的实现是自反的。

ReflBEq.mk.{u_1}
rfl :  {a : α}, (a == a) = true

== 是自反的,即 (a == a) = true

🔗类型类
EquivBEq.{u_1} (α : Type u_1) [BEq α] : Prop
EquivBEq.{u_1} (α : Type u_1) [BEq α] : Prop

EquivBEq 表示 BEq 的实现是一个等价关系。

EquivBEq.mk.{u_1}
symm :  {a b : α}, (a == b) = true  (b == a) = true

继承自父结构。

trans :  {a b c : α}, (a == b) = true  (b == c) = true  (a == c) = true

继承自父结构。

rfl :  {a : α}, (a == a) = true

继承自父结构。

🔗类型类
LawfulHashable.{u} (α : Type u) [BEq α] [Hashable α] : Prop
LawfulHashable.{u} (α : Type u) [BEq α] [Hashable α] : Prop

α 上的 BEq αHashable α 实例彼此兼容。这意味着 a == b 蕴含 hash a = hash b

BEq 实例是合法的,则该性质自动成立。

LawfulHashable.mk.{u}
hash_eq :  (a b : α), (a == b) = true  hash a = hash b

a == b,则 hash a = hash b

🔗定理
hash_eq.{u_1} {α : Type u_1} [BEq α] [Hashable α] [LawfulHashable α] {a b : α} : (a == b) = true hash a = hash b
hash_eq.{u_1} {α : Type u_1} [BEq α] [Hashable α] [LawfulHashable α] {a b : α} : (a == b) = true hash a = hash b

合法的哈希函数遵循其布尔相等性测试。

10.5.2. 排序关系🔗

主要有两种方式为一个类型的值规定次序:

  • Ord 类型类提供三路比较运算符 compare,它可以指出一个值小于、等于或大于另一个值。它返回一个 Ordering

  • LTLE 类为类型提供取值于 Prop 的典范排序关系,且这些关系不必是可判定的。它们用于重载 < 运算符。

🔗类型类
Ord.{u} (α : Type u) : Type u
Ord.{u} (α : Type u) : Type u

Ord α 通过函数 compare : α α Orderingα 提供可计算的全次序。

实例通常具有传递性、自反性和反对称性,但类型类并不强制这些性质。

该类具有派生处理器,因此在归纳类型或结构体后添加 deriving Ord 时,Lean 会尝试创建 一个 Ord 实例。

Ord.mk.{u}
compare : α  α  Ordering

使用 [Ord α] 实例中包含的比较器比较 α 中的两个元素。

compare 方法已被导出,因此使用它时无需显式写出 Ord 命名空间。

🔗定义
compareOn.{u_1, u_2} {β : Type u_1} {α : Sort u_2} [ord : Ord β] (f : α β) (x y : α) : Ordering
compareOn.{u_1, u_2} {β : Type u_1} {α : Sort u_2} [ord : Ord β] (f : α β) (x y : α) : Ordering

通过比较应用某个函数所得的结果来比较两个值。

具体而言,通过比较 f xf y 来比较 xy

示例:

🔗定义
Ord.opposite.{u_1} {α : Type u_1} (ord : Ord α) : Ord α
Ord.opposite.{u_1} {α : Type u_1} (ord : Ord α) : Ord α

反转一个 Ord 实例的次序。

结果是一个 Ord α 实例:当 ord 返回 Ordering.gt 时它返回 Ordering.lt, 当 ord 返回 Ordering.lt 时它返回 Ordering.gt

🔗归纳类型
Ordering : Type
Ordering : Type

按全次序进行比较所得的结果。

被比较项之间的关系可以是:

Ordering.lt : Ordering

小于。

Ordering.eq : Ordering

等于。

Ordering.gt : Ordering

大于。

🔗定义

交换小于与大于这两种比较结果。

示例:

🔗定义

ab 均为 Ordering,则除非 a.eqa.then b 都返回 a;当 a.eq 时,它返回 b。此外,它还具有类似布尔运算 && 的“短路”行为:若 a 不是 .eq,则不会求值表达式 b

这是构造字典序比较函数时很有用的基本操作。对结构体使用 deriving Ord 语法时, 会通过 Ord 实例依次比较各字段,并以等价于 Ordering.then 的方式组合结果。

可使用 compareLex 按字典序组合两个比较函数。

示例:

structure Person where name : String age : Nat -- 先按姓名升序排列;姓名相同时,再按年龄降序排列 instance : Ord Person where compare a b := (compare a.name b.name).then (compare b.age a.age)
#eval Ord.compare (⟨"Gert", 33⟩ : Person) ⟨"Dana", 50⟩
Ordering.gt
#eval Ord.compare (⟨"Gert", 33⟩ : Person) ⟨"Gert", 50⟩
Ordering.gt
#eval Ord.compare (⟨"Gert", 33⟩ : Person) ⟨"Gert", 20⟩
Ordering.lt
🔗定义

检查比较结果是否为 lt

🔗定义

检查比较结果是否为 lteq

🔗定义

检查比较结果是否为 eq

🔗定义

检查比较结果是否不为 eq

🔗定义

检查比较结果是否为 gteq

🔗定义

检查比较结果是否为 gt

🔗定义
compareOfLessAndEq.{u_1} {α : Type u_1} (x y : α) [LT α] [Decidable (x < y)] [DecidableEq α] : Ordering
compareOfLessAndEq.{u_1} {α : Type u_1} (x y : α) [LT α] [Decidable (x < y)] [DecidableEq α] : Ordering

使用可判定的严格小于关系和相等关系求出一个 Ordering

具体而言,若 x < y,结果为 Ordering.lt;若 x = y,结果为 Ordering.eq; 否则结果为 Ordering.gt

compareOfLessAndBEq 使用 BEq 而不是 DecidableEq

🔗定义
compareOfLessAndBEq.{u_1} {α : Type u_1} (x y : α) [LT α] [Decidable (x < y)] [BEq α] : Ordering
compareOfLessAndBEq.{u_1} {α : Type u_1} (x y : α) [LT α] [Decidable (x < y)] [BEq α] : Ordering

使用可判定的严格小于关系和布尔相等性测试求出一个 Ordering

具体而言,若 x < y,结果为 Ordering.lt;若 x == y,结果为 Ordering.eq; 否则结果为 Ordering.gt

compareOfLessAndEq 使用 DecidableEq 而不是 BEq

🔗定义
compareLex.{u_1, u_2} {α : Sort u_1} {β : Sort u_2} (cmp₁ cmp₂ : α β Ordering) (a : α) (b : β) : Ordering
compareLex.{u_1, u_2} {α : Sort u_1} {β : Sort u_2} (cmp₁ cmp₂ : α β Ordering) (a : α) (b : β) : Ordering

使用 cmp₁cmp₂ 按字典序比较 ab

首先用 cmp₁ 比较 ab。若其返回 Ordering.eq,则用 cmp₂ 比较 ab,以打破平局。

若要按字典序组合两个 Ordering,请使用 Ordering.then

语法排序运算符

小于运算符在 LT 类中重载:

term ::= ...
    | 小于关系:`x < y`。

标识符中的记法约定:建议将 `<` 写作 `lt`。term < term

小于等于运算符在 LE 类中重载:

term ::= ...
    | 小于等于关系:`x ≤ y`。

标识符中的记法约定:建议将 `≤` 写作 `le`。term  term

大于和大于等于运算符分别是小于和小于等于运算符的反向形式,不能独立重载:

term ::= ...
    | `a > b` 是 `b < a` 的缩写。

标识符中的记法约定:建议将 `>` 写作 `gt`。term > term
term ::= ...
    | `a ≥ b` 是 `b ≤ a` 的缩写。

标识符中的记法约定:建议将 `≥` 写作 `ge`。term  term
🔗类型类
LT.{u} (α : Type u) : Type u
LT.{u} (α : Type u) : Type u

LT α 是支持记法 x < y(其中 x y : α)的类型类。

LT.mk.{u}
lt : α  α  Prop

严格小于关系:x < y

🔗类型类
LE.{u} (α : Type u) : Type u
LE.{u} (α : Type u) : Type u

LE α 是支持记法 x y(其中 x y : α)的类型类。

LE.mk.{u}
le : α  α  Prop

小于等于关系:x y

可以用以下辅助函数从 Ord 构造 BEqLTLE 实例。 这些辅助函数不会自动成为实例,因为对许多类型而言,自定义关系更为合适。

🔗定义
ltOfOrd.{u_1} {α : Type u_1} [Ord α] : LT α
ltOfOrd.{u_1} {α : Type u_1} [Ord α] : LT α

Ord 实例构造一个 LT 实例;该实例断言 compare 的结果为 Ordering.lt

🔗定义
leOfOrd.{u_1} {α : Type u_1} [Ord α] : LE α
leOfOrd.{u_1} {α : Type u_1} [Ord α] : LE α

Ord 实例构造一个 LE 实例;该实例断言 compare 的结果满足 Ordering.isLE

🔗定义
Ord.toBEq.{u_1} {α : Type u_1} (ord : Ord α) : BEq α
Ord.toBEq.{u_1} {α : Type u_1} (ord : Ord α) : BEq α

Ord 实例构造一个 BEq 实例。

🔗定义
Ord.toLE.{u_1} {α : Type u_1} (ord : Ord α) : LE α
Ord.toLE.{u_1} {α : Type u_1} (ord : Ord α) : LE α

Ord 实例构造一个 LE 实例。

🔗定义
Ord.toLT.{u_1} {α : Type u_1} (ord : Ord α) : LT α
Ord.toLT.{u_1} {α : Type u_1} (ord : Ord α) : LT α

Ord 实例构造一个 LT 实例。

使用 Ord 实例构造 LTLE 实例

Lean 可以自动派生 Ord 实例。 在本例中,Ord Vegetable 实例按字典序比较蔬菜:

structure Vegetable where color : String size : Fin 5 deriving Ord def broccoli : Vegetable where color := "green" size := 2 def sweetPotato : Vegetable where color := "orange" size := 3

使用辅助函数 ltOfOrdleOfOrd,可以定义 LT VegetableLE Vegetable 实例。 这些实例使用 compare 比较蔬菜,并在逻辑上断言结果符合预期。

instance : LT Vegetable := ltOfOrd instance : LE Vegetable := leOfOrd

所得关系是可判定的,因为 Ordering 上的相等性是可判定的:

true#eval broccoli < sweetPotato
true
true#eval broccoli sweetPotato
true
false#eval broccoli < broccoli
false
true#eval broccoli broccoli
true

10.5.2.1. 实例构造🔗

🔗定义
Ord.lex.{u_1, u_2} {α : Type u_1} {β : Type u_2} : Ord α Ord β Ord (α × β)
Ord.lex.{u_1, u_2} {α : Type u_1} {β : Type u_2} : Ord α Ord β Ord (α × β)

根据 αβ 上的次序,构造积类型 α × β 上的字典序。

🔗定义
Ord.lex'.{u_1} {α : Type u_1} (ord₁ ord₂ : Ord α) : Ord α
Ord.lex'.{u_1} {α : Type u_1} (ord₁ ord₂ : Ord α) : Ord α

按字典序组合两个已有实例,构造一个 Ord 实例。

所得实例先用 ord₁ 比较元素;若其返回 Ordering.eq,再用 ord₂ 比较。

函数 compareLex 可以在不构造中间 Ord 实例的情况下完成这种比较。 Ordering.then 可以按字典序组合各次比较的结果。

🔗定义
Ord.on.{u_1, u_2} {β : Type u_1} {α : Type u_2} : Ord β (f : α β) Ord α
Ord.on.{u_1, u_2} {β : Type u_1} {α : Type u_2} : Ord β (f : α β) Ord α

构造一个 Ord 实例,它根据应用 f 所得的结果比较值。

具体而言,ord.on f 根据 ord 比较 f xf y,从而比较 xy

函数 compareOn 可以在不构造中间 Ord 实例的情况下完成这种比较。

10.5.3. 最小值与最大值🔗

MaxMin 提供重载运算符,用于从两个值中选择较大者或较小者。 若 OrdLTLE 实例存在,它们应当与这些运算符保持一致,但并没有强制这一点的机制。

🔗类型类
Min.{u} (α : Type u) : Type u
Min.{u} (α : Type u) : Type u

对类型 α 的两个值执行可重载的最小值操作。

Min.mk.{u}
min : α  α  α

返回两个参数中较小的一个。

🔗类型类
Max.{u} (α : Type u) : Type u
Max.{u} (α : Type u) : Type u

对类型 α 的两个值执行可重载的最大值操作。

Max.mk.{u}
max : α  α  α

返回两个参数中较大的一个。

给定一个 LE.le 可判定的 LE α 实例,可以使用辅助函数 minOfLemaxOfLe 创建合适的 Min αMax α 实例。 它们可以用作 Lean.Parser.Command.declaration : commandinstance 声明的右侧。

🔗定义
minOfLe.{u_1} {α : Type u_1} [LE α] [DecidableRel LE.le] : Min α
minOfLe.{u_1} {α : Type u_1} [LE α] [DecidableRel LE.le] : Min α

从可判定的 操作构造一个 Min 实例。

🔗定义
maxOfLe.{u_1} {α : Type u_1} [LE α] [DecidableRel LE.le] : Max α
maxOfLe.{u_1} {α : Type u_1} [LE α] [DecidableRel LE.le] : Max α

从可判定的 操作构造一个 Max 实例。

10.5.4. 可判定性🔗

如果一个命题可以通过算法检查,那么它就是可判定的 排中律意味着每个命题非真即假,但它没有提供检查究竟是哪种情形成立的方法;而这种检查往往很有用。 默认情况下,作用域中只有可生成代码的算法式 Decidable 实例;打开 Classical 命名空间则会使每个命题都可判定。

🔗归纳类型
Decidable (p : Prop) : Type
Decidable (p : Prop) : Type

要么给出命题 p 为真的证明,要么给出命题 p 为假的证明。这等价于一个 Bool, 再配上该 Booltrue 当且仅当 p 为真的证明。

Decidable 实例主要通过 if 表达式和 decide 策略使用。在条件表达式中,命题的 Decidable 实例用于选择分支。运行时,这种分类生成的代码与基于 Bool 的条件表达式 所生成的代码相同。在证明中,decide 策略会合成 Decidable p 的实例,尝试将其归约为 isTrue h,若成功便使用证明 h 完成目标。

由于 Decidable 携带数据,在编写左侧包含 Decidable 实例的 @[simp] 引理时,最好使用 {_ : Decidable p} 而不是 [Decidable p],这样非典范实例可以通过合一找到,而不是通过 实例合成找到。

Decidable.isFalse {p : Prop} (h : ¬p) : Decidable p

通过提供 ¬p 的证明来证明 p 可判定。

Decidable.isTrue {p : Prop} (h : p) : Decidable p

通过提供 p 的证明来证明 p 可判定。

🔗定义
DecidablePred.{u} {α : Sort u} (r : α Prop) : Sort (max 1 u)
DecidablePred.{u} {α : Sort u} (r : α Prop) : Sort (max 1 u)

可判定谓词。

如果对每个可能的参数,相应命题都是 Decidable,那么该谓词就是可判定的。

🔗定义
DecidableRel.{u, v} {α : Sort u} {β : Sort v} (r : α β Prop) : Sort (max (max 1 u) v)
DecidableRel.{u, v} {α : Sort u} {β : Sort v} (r : α β Prop) : Sort (max (max 1 u) v)

可判定关系。

如果对所有可能的参数,相应命题都是 Decidable,那么该关系就是可判定的。

🔗定义
DecidableEq.{u} (α : Sort u) : Sort (max 1 u)
DecidableEq.{u} (α : Sort u) : Sort (max 1 u)

一个类型的任意元素之间的命题相等性都是 Decidable

换言之,DecidableEq α 的实例提供了一种方法,可对所有 a b : α 判定命题 a = b

🔗定义
DecidableLT.{u} (α : Type u) [LT α] : Type u
DecidableLT.{u} (α : Type u) [LT α] : Type u

DecidableRel (· < · : α α Prop) 的缩写。

🔗定义
DecidableLE.{u} (α : Type u) [LE α] : Type u
DecidableLE.{u} (α : Type u) [LE α] : Type u

DecidableRel (· · : α α Prop) 的缩写。

🔗定义
Decidable.decide (p : Prop) [h : Decidable p] : Bool
Decidable.decide (p : Prop) [h : Decidable p] : Bool

将可判定命题转换为 Bool

如果 p : Prop 可判定,那么 decide p : Boolp 为真时是 true,在 p 为假时是 false

🔗定义
Decidable.byCases.{u} {p : Prop} {q : Sort u} [dec : Decidable p] (h1 : p q) (h2 : ¬p q) : q
Decidable.byCases.{u} {p : Prop} {q : Sort u} [dec : Decidable p] (h1 : p q) (h2 : ¬p q) : q

当命题 p 可判定,并且无论 p 为真还是为假都足以构造 q 时,构造一个 q

这是依赖式 if-then-else 运算符 dite 的同义形式。

排中律与 Decidable

NatNat 的函数之间的相等性不可判定:

example (f g : Nat Nat) : Decidable (f = g) := failed to synthesize instance of type class Decidable (f = g) Hint: Type class instance resolution failures can be inspected with the `set_option trace.Meta.synthInstance true` command.inferInstance
failed to synthesize instance of type class
  Decidable (f = g)

Hint: Type class instance resolution failures can be inspected with the `set_option trace.Meta.synthInstance true` command.

打开 Classical 会使每个命题都可判定;不过,使用这一事实的声明和示例必须标记为 Lean.Parser.Command.declaration : commandnoncomputable,以表明不应为它们生成代码。

open Classical noncomputable example (f g : Nat Nat) : Decidable (f = g) := inferInstance

10.5.5. 带默认值的类型🔗

🔗类型类
Inhabited.{u} (α : Sort u) : Sort (max 1 u)
Inhabited.{u} (α : Sort u) : Sort (max 1 u)

Inhabited α 是一个类型类,表示 α 有一个指定元素,称为 (default : α)。这种类型有时 称为“居留类型”。

需要在“定义域之外”被调用时仍返回该类型值的函数会使用这个类。例如,若 arr : Array α, 则 Array.get! arr i : αi 越界时会报告 panic;但这不会终止程序,因此函数仍必须返回 一个 α 类型的值(逻辑一致性事实上也要求如此),此时它返回 default

Inhabited.mk.{u}
default : α

default 生成任意居留类型的“默认”元素。该元素没有任何特别规定的性质,但通常是全零值。

🔗归纳谓词
Nonempty.{u} (α : Sort u) : Prop
Nonempty.{u} (α : Sort u) : Prop

Nonempty α 是一个类型类,表示 α 不是空类型,即该类型中存在一个元素。它与 Inhabited α 的区别在于,Nonempty α 是一个 Prop,所以它实际上不携带 α 的元素, 只携带“存在这种元素”的证明。 给定 Nonempty α,可以使用 Classical.choice 以非构造方式构造 α 的元素。

Nonempty.intro.{u} {α : Sort u} (val : α) : Nonempty α

如果 val : α,那么 α 非空。

10.5.6. 至多单元素类型🔗

🔗类型类
Subsingleton.{u} (α : Sort u) : Prop
Subsingleton.{u} (α : Sort u) : Prop

_子单例_是至多有一个元素的类型:它要么为空,要么有唯一元素。

由于证明无关性,所有命题都是子单例:假命题为空,而真命题的任意两个证明彼此相等。 某些非命题类型也是子单例。

Subsingleton.intro.{u}

通过证明任意两个元素相等来证明 α 是子单例。

allEq :  (a b : α), a = b

子单例中的任意两个元素都相等。

🔗定理
Subsingleton.elim.{u} {α : Sort u} [h : Subsingleton α] (a b : α) : a = b
Subsingleton.elim.{u} {α : Sort u} [h : Subsingleton α] (a b : α) : a = b

如果一个类型是子单例,那么它的所有元素都相等。

🔗定理
Subsingleton.helim.{u} {α β : Sort u} [h₁ : Subsingleton α] (h₂ : α = β) (a : α) (b : β) : a b
Subsingleton.helim.{u} {α β : Sort u} [h₁ : Subsingleton α] (h₂ : α = β) (a : α) (b : β) : a b

如果两个类型相等,并且其中一个是子单例,那么它们的所有元素都 异质相等

10.5.7. 算术与位运算符🔗

🔗类型类
Zero.{u} (α : Type u) : Type u
Zero.{u} (α : Type u) : Type u

具有零元素的类型。

Zero.mk.{u}
zero : α

该类型的零元素。

🔗类型类
NeZero.{u_1} {R : Type u_1} [Zero R] (n : R) : Prop
NeZero.{u_1} {R : Type u_1} [Zero R] (n : R) : Prop

n 0 的类型类版本。

NeZero.mk.{u_1}
out : n  0

命题 n 不等于零。

🔗类型类
HAdd.{u, v, w} (α : Type u) (β : Type v) (γ : outParam (Type w)) : Type (max (max u v) w)
HAdd.{u, v, w} (α : Type u) (β : Type v) (γ : outParam (Type w)) : Type (max (max u v) w)

异质加法记法的类型类。 它启用记法 a + b : γ,其中 a : αb : β

HAdd.mk.{u, v, w}
hAdd : α  β  γ

a + b 计算 ab 的和。该记法的含义取决于类型。

🔗类型类
Add.{u} (α : Type u) : Type u
Add.{u} (α : Type u) : Type u

HAdd 的同质版本:a + b : α,其中 a b : α

Add.mk.{u}
add : α  α  α

a + b 计算 ab 的和。参见 HAdd

🔗类型类
HSub.{u, v, w} (α : Type u) (β : Type v) (γ : outParam (Type w)) : Type (max (max u v) w)
HSub.{u, v, w} (α : Type u) (β : Type v) (γ : outParam (Type w)) : Type (max (max u v) w)

异质减法记法的类型类。 它启用记法 a - b : γ,其中 a : αb : β

HSub.mk.{u, v, w}
hSub : α  β  γ

a - b 计算 ab 的差。该记法的含义取决于类型。

  • 对自然数,此运算在 0 处饱和:当 a b 时,a - b = 0

🔗类型类
Sub.{u} (α : Type u) : Type u
Sub.{u} (α : Type u) : Type u

HSub 的同质版本:a - b : α,其中 a b : α

Sub.mk.{u}
sub : α  α  α

a - b 计算 ab 的差。参见 HSub

🔗类型类
HMul.{u, v, w} (α : Type u) (β : Type v) (γ : outParam (Type w)) : Type (max (max u v) w)
HMul.{u, v, w} (α : Type u) (β : Type v) (γ : outParam (Type w)) : Type (max (max u v) w)

异质乘法记法的类型类。 它启用记法 a * b : γ,其中 a : αb : β

HMul.mk.{u, v, w}
hMul : α  β  γ

a * b 计算 ab 的积。该记法的含义取决于类型。

🔗类型类
SMul.{u, v} (M : Type u) (α : Type v) : Type (max u v)
SMul.{u, v} (M : Type u) (α : Type v) : Type (max u v)

标量乘法运算的类型类,记作 (输入 \bu)。

SMul.mk.{u, v}
smul : M  α  α

m a : α 表示 m : Ma : α 的积。该记法的含义取决于类型,但预期用于左作用。

🔗类型类
Mul.{u} (α : Type u) : Type u
Mul.{u} (α : Type u) : Type u

HMul 的同质版本:a * b : α,其中 a b : α

Mul.mk.{u}
mul : α  α  α

a * b 计算 ab 的积。参见 HMul

🔗类型类
HDiv.{u, v, w} (α : Type u) (β : Type v) (γ : outParam (Type w)) : Type (max (max u v) w)
HDiv.{u, v, w} (α : Type u) (β : Type v) (γ : outParam (Type w)) : Type (max (max u v) w)

异质除法记法的类型类。 它启用记法 a / b : γ,其中 a : αb : β

HDiv.mk.{u, v, w}
hDiv : α  β  γ

a / b 计算 a 除以 b 的结果。该记法的含义取决于类型。

  • NatIntRatReal 等大多数类型,a / 0 定义为 0

  • Nata / b 向下取整。

  • Int,当 b 为正时 a / b 向下取整,当 b 为负时向上取整。其实现为 Int.ediv,这是满足 a % b + b * (a / b) = a 且在 b 0 时满足 0 a % b < natAbs b 的唯一函数。函数 Int.fdiv(向下取整)和 Int.tdiv (向零截断)提供其他取整约定。

  • Floata / 0 遵循 IEEE 754 除法语义,通常得到 infnan

🔗类型类
Div.{u} (α : Type u) : Type u
Div.{u} (α : Type u) : Type u

HDiv 的同质版本:a / b : α,其中 a b : α

Div.mk.{u}
div : α  α  α

a / b 计算 a 除以 b 的结果。参见 HDiv

🔗类型类
Dvd.{u_1} (α : Type u_1) : Type u_1
Dvd.{u_1} (α : Type u_1) : Type u_1

运算(输入 \|)的记法类型类;该运算表示整除。

Dvd.mk.{u_1}
dvd : α  α  Prop

整除。a b(输入 \|)表示存在某个 c,使得 b = a * c

🔗类型类
HMod.{u, v, w} (α : Type u) (β : Type v) (γ : outParam (Type w)) : Type (max (max u v) w)
HMod.{u, v, w} (α : Type u) (β : Type v) (γ : outParam (Type w)) : Type (max (max u v) w)

异质模/余数记法的类型类。 它启用记法 a % b : γ,其中 a : αb : β

HMod.mk.{u, v, w}
hMod : α  β  γ

a % b 计算 a 除以 b 的余数。该记法的含义取决于类型。

  • NatInt,它满足 a % b + b * (a / b) = a,且 a % 0 定义为 a

🔗类型类
Mod.{u} (α : Type u) : Type u
Mod.{u} (α : Type u) : Type u

HMod 的同质版本:a % b : α,其中 a b : α

Mod.mk.{u}
mod : α  α  α

a % b 计算 a 除以 b 的余数。参见 HMod

🔗类型类
HPow.{u, v, w} (α : Type u) (β : Type v) (γ : outParam (Type w)) : Type (max (max u v) w)
HPow.{u, v, w} (α : Type u) (β : Type v) (γ : outParam (Type w)) : Type (max (max u v) w)

异质幂运算记法的类型类。 它启用记法 a ^ b : γ,其中 a : αb : β

HPow.mk.{u, v, w}
hPow : α  β  γ

a ^ b 计算 ab 次幂。该记法的含义取决于类型。

🔗类型类
Pow.{u, v} (α : Type u) (β : Type v) : Type (max u v)
Pow.{u, v} (α : Type u) (β : Type v) : Type (max u v)

HPow 的同质版本:a ^ b : α,其中 a : αb : β。(右参数与左参数类型不必相同, 因为即使在同质情形中也常有这种需求。)

类型可以通过提供 NatPowHomogeneousPow 的实例来选择特定的默认行为:

  • NatPow 用于指数优先为 Nat 的类型。

  • HomogeneousPow 用于底数和指数优先具有相同类型的类型。

Pow.mk.{u, v}
pow : α  β  α

a ^ b 计算 ab 次幂。参见 HPow

🔗类型类
NatPow.{u} (α : Type u) : Type u
NatPow.{u} (α : Type u) : Type u

指数为 NatPow 同质版本。此类的用途是提供默认 Pow 实例,使精译过程中可以将 指数特化为 Nat

例如,如果 x ^ 2 应优先精译为 2 : Nat,那么 x 的类型应提供此类的实例。

NatPow.mk.{u}
pow : α  Nat  α

a ^ n 计算 an 次幂,其中 n : Nat。参见 Pow

🔗类型类
HomogeneousPow.{u} (α : Type u) : Type u
HomogeneousPow.{u} (α : Type u) : Type u

指数与底数类型相同的完全同质 Pow 版本。此类的用途是提供默认 Pow 实例,使精译过程中 可以将指数特化为与底数相同的类型。也就是说,当 x ^ y 应精译为 xy 具有相同 类型时,该类型应提供此类的实例。

例如,Float 类型提供此类的实例,因此 (2.2 ^ 2.2 : Float) 这样的表达式可以精译。

HomogeneousPow.mk.{u}
pow : α  α  α

a ^ b 计算 ab 次幂,其中 ab 具有相同类型。

🔗类型类
HShiftLeft.{u, v, w} (α : Type u) (β : Type v) (γ : outParam (Type w)) : Type (max (max u v) w)
HShiftLeft.{u, v, w} (α : Type u) (β : Type v) (γ : outParam (Type w)) : Type (max (max u v) w)

a <<< b : γ 记法背后的类型类,其中 a : αb : β

HShiftLeft.mk.{u, v, w}
hShiftLeft : α  β  γ

a <<< b 计算将 a 左移 b 位的结果。该记法的含义取决于类型。

  • Nat,这等价于 a * 2 ^ b

  • UInt8 及其他固定位宽无符号类型,计算相同,但结果会截断到相应位宽。

🔗类型类
ShiftLeft.{u} (α : Type u) : Type u
ShiftLeft.{u} (α : Type u) : Type u

HShiftLeft 的同质版本:a <<< b : α,其中 a b : α

ShiftLeft.mk.{u}
shiftLeft : α  α  α

a <<< b : α 的实现。参见 HShiftLeft

🔗类型类
HShiftRight.{u, v, w} (α : Type u) (β : Type v) (γ : outParam (Type w)) : Type (max (max u v) w)
HShiftRight.{u, v, w} (α : Type u) (β : Type v) (γ : outParam (Type w)) : Type (max (max u v) w)

a >>> b : γ 记法背后的类型类,其中 a : αb : β

HShiftRight.mk.{u, v, w}
hShiftRight : α  β  γ

a >>> b 计算将 a 右移 b 位的结果。该记法的含义取决于类型。

  • NatUInt8 等固定位宽无符号类型,这等价于 a / 2 ^ b

🔗类型类
ShiftRight.{u} (α : Type u) : Type u
ShiftRight.{u} (α : Type u) : Type u

HShiftRight 的同质版本:a >>> b : α,其中 a b : α

ShiftRight.mk.{u}
shiftRight : α  α  α

a >>> b : α 的实现。参见 HShiftRight

🔗类型类
Neg.{u} (α : Type u) : Type u
Neg.{u} (α : Type u) : Type u

取负记法的类型类。 它启用记法 -a : α,其中 a : α

Neg.mk.{u}
neg : α  α

-a 计算 a 的负值或相反值。该记法的含义取决于类型。

🔗类型类
HAnd.{u, v, w} (α : Type u) (β : Type v) (γ : outParam (Type w)) : Type (max (max u v) w)
HAnd.{u, v, w} (α : Type u) (β : Type v) (γ : outParam (Type w)) : Type (max (max u v) w)

a &&& b : γ 记法背后的类型类,其中 a : αb : β

HAnd.mk.{u, v, w}
hAnd : α  β  γ

a &&& b 计算 ab 的逐位与。该记法的含义取决于类型。

🔗类型类
AndOp.{u} (α : Type u) : Type u
AndOp.{u} (α : Type u) : Type u

HAnd 的同质版本:a &&& b : α,其中 a b : α。 (之所以称为 AndOp,是因为 And 已用于命题合取。)

AndOp.mk.{u}
and : α  α  α

a &&& b : α 的实现。参见 HAnd

🔗类型类
HOr.{u, v, w} (α : Type u) (β : Type v) (γ : outParam (Type w)) : Type (max (max u v) w)
HOr.{u, v, w} (α : Type u) (β : Type v) (γ : outParam (Type w)) : Type (max (max u v) w)

a ||| b : γ 记法背后的类型类,其中 a : αb : β

HOr.mk.{u, v, w}
hOr : α  β  γ

a ||| b 计算 ab 的逐位或。该记法的含义取决于类型。

🔗类型类
OrOp.{u} (α : Type u) : Type u
OrOp.{u} (α : Type u) : Type u

HOr 的同质版本:a ||| b : α,其中 a b : α。 (之所以称为 OrOp,是因为 Or 已用于命题析取。)

OrOp.mk.{u}
or : α  α  α

a ||| b : α 的实现。参见 HOr

🔗类型类
HXor.{u, v, w} (α : Type u) (β : Type v) (γ : outParam (Type w)) : Type (max (max u v) w)
HXor.{u, v, w} (α : Type u) (β : Type v) (γ : outParam (Type w)) : Type (max (max u v) w)

a ^^^ b : γ 记法背后的类型类,其中 a : αb : β

HXor.mk.{u, v, w}
hXor : α  β  γ

a ^^^ b 计算 ab 的逐位异或。该记法的含义取决于类型。

🔗类型类
XorOp.{u} (α : Type u) : Type u
XorOp.{u} (α : Type u) : Type u

HXor 的同质版本:a ^^^ b : α,其中 a b : α

XorOp.mk.{u}
xor : α  α  α

a ^^^ b : α 的实现。参见 HXor

10.5.8. 追加🔗

🔗类型类
HAppend.{u, v, w} (α : Type u) (β : Type v) (γ : outParam (Type w)) : Type (max (max u v) w)
HAppend.{u, v, w} (α : Type u) (β : Type v) (γ : outParam (Type w)) : Type (max (max u v) w)

异质追加记法的类型类。 它启用记法 a ++ b : γ,其中 a : αb : β

HAppend.mk.{u, v, w}
hAppend : α  β  γ

a ++ bab 的连接结果,通常读作“追加”。该记法的含义取决于类型。

🔗类型类
Append.{u} (α : Type u) : Type u
Append.{u} (α : Type u) : Type u

HAppend 的同质版本:a ++ b : α,其中 a b : α

Append.mk.{u}
append : α  α  α

a ++ bab 的连接结果。参见 HAppend

10.5.9. 数据查找🔗

🔗类型类
GetElem.{u, v, w} (coll : Type u) (idx : Type v) (elem : outParam (Type w)) (valid : outParam (coll idx Prop)) : Type (max (max u v) w)
GetElem.{u, v, w} (coll : Type u) (idx : Type v) (elem : outParam (Type w)) (valid : outParam (coll idx Prop)) : Type (max (max u v) w)

GetElemGetElem? 类实现元素查找记法,具体包括 xs[i]xs[i]?xs[i]!xs[i]'p

这两个类都以 collidxelem 类型为索引,它们分别是容器、索引和元素类型。 一个容器可以支持使用多种索引类型进行查找。关系 valid 决定索引何时保证有效;有效索引 的查找保证不会失败。

例如,数组的实例形如 GetElem (Array α) Nat α (fun xs i => i < xs.size)。换言之,给定数组 xs 和自然数 i,当 valid xs i 成立时,xs[i] 返回一个 α;这里 valid xs ii 小于数组大小时为真。Array 还支持使用 USize 而非 Nat 索引。无论哪种情况,由于边界 在编译时检查,运行时都不需要检查。

对于 xs[i](其中 xs : colli : idx),Lean 会寻找 GetElem coll idx elem valid 的实例,并据此推断返回类型 elem 以及保证 xs[i] 产生有效 elem 值所需的旁条件 valid。系统调用 get_elem_tactic 策略自动证明有效性;xs[i]'p 记法则使用证明 p 满足有效性条件。若证明 p 很长,通常更容易用 have 将其放入上下文, 因为 get_elem_tactic 会尝试 assumption

证明旁条件 valid xs i 会自动交给 get_elem_tactic;可以用 macro_rulesget_elem_tactic_extensible 添加更多分支来扩展该策略。

xs[i]?xs[i]! 不产生证明义务:前者返回 Option elem,以 none 表示值不存在;后者 返回 elem,但在值不存在时会 panic,并根据 Inhabited elem 实例返回 default : elem。 这些操作由 GetElem? 类提供;只要 valid xs i 总是可判定,就可以从 GetElem 类生成默认 实例。

重要实例包括:

  • arr[i] : α,其中 arr : Array αi : Nati : USize:执行数组索引,不做运行时 边界检查,并产生证明旁目标 i < arr.size

  • l[i] : α,其中 l : List αi : Nat:索引列表,并产生证明旁目标 i < l.length

GetElem.mk.{u, v, w}
getElem : (xs : coll)  (i : idx)  valid xs i  elem

语法 arr[i] 获取容器 arr 的第 i 个元素。如果应用存在证明旁条件, get_elem_tactic 策略会自动推断它们。

🔗类型类
GetElem?.{u, v, w} (coll : Type u) (idx : Type v) (elem : outParam (Type w)) (valid : outParam (coll idx Prop)) : Type (max (max u v) w)
GetElem?.{u, v, w} (coll : Type u) (idx : Type v) (elem : outParam (Type w)) (valid : outParam (coll idx Prop)) : Type (max (max u v) w)

GetElemGetElem? 类实现元素查找记法,具体包括 xs[i]xs[i]?xs[i]!xs[i]'p。容器、索引、元素类型及有效性关系的含义与 GetElem 相同。

GetElem?.mk.{u, v, w}
getElem : (xs : coll)  (i : idx)  valid xs i  elem

继承自父结构。

getElem? : coll  idx  Option elem

语法 arr[i]? 获取容器 arr 的第 i 个元素;若元素存在则包装在 some 中,否则返回 none

getElem! : [Inhabited elem]  coll  idx  elem

语法 arr[i]! 获取容器 arr 的第 i 个元素;若元素存在则返回它,否则在运行时 panic, 并返回 Inhabited elem 中的 default 项。

🔗类型类
LawfulGetElem.{u, v, w} (cont : Type u) (idx : Type v) (elem : outParam (Type w)) (dom : outParam (cont idx Prop)) [ge : GetElem? cont idx elem dom] : Prop
LawfulGetElem.{u, v, w} (cont : Type u) (idx : Type v) (elem : outParam (Type w)) (dom : outParam (cont idx Prop)) [ge : GetElem? cont idx elem dom] : Prop

合法的 GetElem? 实例(它扩展 GetElem)应使可能失败的 GetElem?.getElem?GetElem?.getElem! 运算符在有效性谓词成立时成功,在不成立时失败。

LawfulGetElem.mk.{u, v, w}
getElem?_def :  (c : cont) (i : idx) [inst : Decidable (dom c i)], c[i]? = if h : dom c i then some c[i] else none

GetElem?.getElem? 在有效性谓词成立时成功,否则失败。

getElem!_def :  [inst : Inhabited elem] (c : cont) (i : idx),
  c[i]! =
    match c[i]? with
    | some e => e
    | none => default

GetElem?.getElem! 的成败与 GetElem?.getElem? 的成败一致。