Lean 语言参考手册

20.16. 数组🔗

Array 类型表示元素序列,可以通过其在序列中的位置进行访问。 Lean 对数组提供了专门支持:

  • 它有一个逻辑模型,用元素列表来规定其行为,从而给出各个数组操作的含义。

  • 它在编译后的代码中有一种经过优化的运行时表示,即 动态数组,Lean 运行时还会专门优化数组操作。

  • 可以使用 数组字面量语法 来书写数组。

在编译后的代码中,数组可以比列表或其他序列高效得多。 这部分是因为它具有良好的局部性:序列中的所有元素都在内存中彼此相邻,因此处理器缓存可以被高效利用。 更重要的是,如果一个数组只有唯一引用,那么原本需要复制或分配数据结构的操作就可以通过原地修改来实现。 当 Lean 代码以始终只有唯一引用的方式使用数组时(也就是 线性地 使用它),便能避免持久化数据结构的性能开销,同时依旧像普通纯函数式程序一样易于编写、阅读与证明性质。

20.16.1. 逻辑模型🔗

🔗结构体
Array.{u} (α : Type u) : Type u
Array.{u} (α : Type u) : Type u

Array α动态数组 的类型,其中元素来自 α。该类型在运行时有特殊支持。

数组在不共享时性能最佳。只要对数组的引用不超过一次,所有更新都将_破坏性地_执行。这导致性能与命令式编程语言中的可变数组相当。

数组有大小和容量。大小是数组中存在的元素数量,而容量是当前为元素分配的内存量。可以通过 Array.size 访问大小,但无法从Lean 代码中观察到容量。 Array.emptyWithCapacity n 创建一个等于 #[] 的数组,但内部分配了一个容量为 n 的数组。当大小超过容量时,需要分配以扩大数组。

从证明的角度来看,Array α 只是 List α 的包装。

Array.mk.{u}

List α 转换为 Array α

推荐使用函数 List.toArray

在运行时,该构造子由 List.toArrayImpl 覆盖,其时间复杂度关于列表长度为 O(n)

toList : List α

Array α 转换为按相同顺序包含相同元素的 List α

在运行时,它由 Array.toListImpl 实现,其时间复杂度关于数组长度为 O(n)

数组的逻辑模型是一个只有单个字段的结构体,该字段是元素列表。 这使得在较低层次上规定和证明数组处理函数的性质时更加方便。

20.16.2. 运行时表示🔗

Lean 的数组是 动态数组:它们是一段具有既定容量的连续内存块,通常其中不会全部被占用。 只要数组中的元素个数小于容量,就可以在末尾追加新元素,而无需重新分配或移动数据。 向没有剩余空间的数组中添加元素时,会触发一次将容量翻倍的重新分配。 其摊还开销与数组大小呈线性关系。 数组中的值按 外部函数接口一节所述的方式表示。

m_header Lean 对象头 m_size 字节数size_t m_capacity 已分配空间size_t m_data 数组数据lean_object * 数组
数组的内存布局

在对象头之后,数组包含:

大小

当前存储在数组中的对象个数

容量

为数组分配的内存中可容纳的对象个数

数据

数组中的值

Lean 运行时中的许多数组函数都会通过查看对象头中的引用计数,来检查自己是否独占其参数。 如果是,并且数组容量足够,那么就可以直接修改现有数组,而无需分配新的内存。 否则,就必须分配一个新数组。

20.16.2.1. 性能说明🔗

尽管 Array.mkArray.toList 看起来只是普通的构造子与投影,但在编译后的代码中,它们都需要 与数组大小成线性关系的时间。 这是因为在链表与紧凑数组之间转换时,必然需要访问每一个元素。

可变数组可用于编写非常高效的代码。 不过,它们并不是好的持久化数据结构。 更新共享数组时无法使用原地修改,并且需要耗费与数组大小成线性关系的时间。 在性能关键的代码中使用数组时,务必确保它们是 线性地 使用的。

20.16.3. 语法🔗

数组字面量允许直接在代码中书写数组。 它们既可用于表达式上下文,也可用于模式上下文。

语法数组字面量

数组字面量以 #[ 开始,包含一串以逗号分隔的项,并以 ] 结束。

term ::= ...
    | #[term,*]
数组字面量

数组字面量既可以用作表达式,也可以用作模式。

def oneTwoThree : Array Nat := #[1, 2, 3] some 2#eval match oneTwoThree with | #[x, y, z] => some ((x + z) / y) | _ => none

此外,还可以用下列语法提取 子数组

语法子数组

起始下标后跟一个冒号,会构造出一个子数组,包含从起始下标开始(含该位置)直到末尾的值:

term ::= ...
    | term[term :]

同时提供起始与结束下标时,会构造出一个子数组,包含从起始下标(含)到结束下标(不含)的值:

term ::= ...
    | term[term : term]
子数组语法

数组 ten 包含前十个自然数。

def ten : Array Nat := .range 10

可以使用子数组语法构造一个表示 ten 后半部分的子数组:

#[5, 6, 7, 8, 9].toSubarray#eval ten[5:]
#[5, 6, 7, 8, 9].toSubarray

类似地,通过给出结束位置,可以构造出包含 2 到 5 的子数组:

#[2, 3, 4, 5].toSubarray#eval ten[2:6]
#[2, 3, 4, 5].toSubarray

由于子数组仅存储其在底层数组中所关注的起止下标,因此可以恢复出该数组本身:

true#eval ten[2:6].array == ten
true

20.16.4. 接口参考🔗

20.16.4.1. 构造数组🔗

🔗定义
Array.empty.{u} {α : Type u} : Array α
Array.empty.{u} {α : Type u} : Array α

构造一个新的空数组,初始容量为 0

使用Array.emptyWithCapacity创建具有更大初始容量的阵列。

🔗定义
Array.emptyWithCapacity.{u} {α : Type u} (c : Nat) : Array α
Array.emptyWithCapacity.{u} {α : Type u} (c : Nat) : Array α

构造一个新的空数组,初始容量为 c

🔗定义
Array.singleton.{u} {α : Type u} (v : α) : Array α
Array.singleton.{u} {α : Type u} (v : α) : Array α

构造一个包含 v 的单元素数组。

示例:

🔗定义

构造一个数组,其中包含从 0n 的所有数字(不包括)。

示例:

  • Array.range 5 := #[0, 1, 2, 3, 4]

  • Array.range 0 := #[]

  • Array.range 1 := #[0]

🔗定义
Array.range' (start size : Nat) (step : Nat := 1) : Array Nat
Array.range' (start size : Nat) (step : Nat := 1) : Array Nat

构造一个大小为 size 的数字数组,从 start 开始,每个元素增加 step

换句话说,Array.range' start size step#[start, start+step, ..., start+(len-1)*step]

示例:

🔗定义

按顺序返回 Fin n 中所有元素的数组,从 0 开始。

示例:

🔗定义
Array.ofFn.{u} {α : Type u} {n : Nat} (f : Fin n α) : Array α
Array.ofFn.{u} {α : Type u} {n : Nat} (f : Fin n α) : Array α

通过按顺序将 f 应用于每个潜在索引(从 0 开始)来创建数组。

示例:

  • Array.ofFn (n := 3) toString = #["0", "1", "2"]

  • Array.ofFn (fun i => #["red", "green", "blue"].get i.val i.isLt) = #["red", "green", "blue"]

🔗定义
Array.replicate.{u} {α : Type u} (n : Nat) (v : α) : Array α
Array.replicate.{u} {α : Type u} (n : Nat) (v : α) : Array α

创建一个数组,其中 n 个元素均为 v

对应的List函数为List.replicate

示例:

🔗定义
Array.append.{u} {α : Type u} (as bs : Array α) : Array α
Array.append.{u} {α : Type u} (as bs : Array α) : Array α

添加两个数组。通常通过 ++ 运算符使用。

追加数组所需的时间与第二个数组的长度成正比。

示例:

  • #[1, 2, 3] ++ #[4, 5] = #[1, 2, 3, 4, 5]

  • #[] ++ #[4, 5] = #[4, 5]

  • #[1, 2, 3] ++ #[] = #[1, 2, 3]

🔗定义
Array.appendList.{u} {α : Type u} (as : Array α) (bs : List α) : Array α
Array.appendList.{u} {α : Type u} (as : Array α) (bs : List α) : Array α

追加一个数组和一个列表。

花费的时间与列表的长度成正比。

示例:

🔗定义
Array.leftpad.{u} {α : Type u} (n : Nat) (a : α) (xs : Array α) : Array α
Array.leftpad.{u} {α : Type u} (n : Nat) (a : α) (xs : Array α) : Array α

在左侧填充 xs : Array α,并重复出现 a : α,直到其大小为 n。如果 xs 已至少具有 n 元素,则返回未修改的元素。

示例:

  • #[1, 2, 3].leftpad 5 0 = #[0, 0, 1, 2, 3]

  • #["red", "green", "blue"].leftpad 4 "blank" = #["blank", "red", "green", "blue"]

  • #["red", "green", "blue"].leftpad 3 "blank" = #["red", "green", "blue"]

  • #["red", "green", "blue"].leftpad 1 "blank" = #["red", "green", "blue"]

🔗定义
Array.rightpad.{u} {α : Type u} (n : Nat) (a : α) (xs : Array α) : Array α
Array.rightpad.{u} {α : Type u} (n : Nat) (a : α) (xs : Array α) : Array α

在右侧填充 xs : Array α,并重复出现 a : α,直到其长度为 n。如果 l 已至少具有 n 元素,则返回未修改的元素。

示例:

  • #[1, 2, 3].rightpad 5 0 = #[1, 2, 3, 0, 0]

  • #["red", "green", "blue"].rightpad 4 "blank" = #["red", "green", "blue", "blank"]

  • #["red", "green", "blue"].rightpad 3 "blank" = #["red", "green", "blue"]

  • #["red", "green", "blue"].rightpad 1 "blank" = #["red", "green", "blue"]

20.16.4.2. 大小🔗

🔗定义
Array.size.{u} {α : Type u} (a : Array α) : Nat
Array.size.{u} {α : Type u} (a : Array α) : Nat

获取数组中存储的元素数。

这是一个缓存值,因此要访问的是O(1)。为数组分配的空间(称为“容量”)至少与其大小一样大,但也可能更大。数组的容量是Lean 代码无法观察到的内部细节。

🔗定义
Array.usize.{u} {α : Type u} (xs : Array α) : USize
Array.usize.{u} {α : Type u} (xs : Array α) : USize

以平台本机无符号整数形式返回数组的大小。

这是 Array.size 的低级版本,直接查询运行时系统的数组表示。虽然这无法证明,但 Array.usize 始终返回数组的确切大小,因为该实现仅支持大小小于 USize.size 的数组。

🔗定义
Array.isEmpty.{u} {α : Type u} (xs : Array α) : Bool
Array.isEmpty.{u} {α : Type u} (xs : Array α) : Bool

检查数组是否为空。

如果数组的大小为 0,则数组为空。

示例:

20.16.4.3. 查找🔗

🔗定义
Array.extract.{u_1} {α : Type u_1} (as : Array α) (start : Nat := 0) (stop : Nat := as.size) : Array α
Array.extract.{u_1} {α : Type u_1} (as : Array α) (start : Nat := 0) (stop : Nat := as.size) : Array α

返回 as 从索引 startstop(不包括)的切片。生成的数组的大小为 (min stop as.size) - start

如果 start 大于或等于 stop,则结果为空。如果 stop 大于 as 的大小,则使用该大小。

示例:

  • #[0, 1, 2, 3, 4].extract 1 3 = #[1, 2]

  • #[0, 1, 2, 3, 4].extract 1 30 = #[1, 2, 3, 4]

  • #[0, 1, 2, 3, 4].extract 0 0 = #[]

  • #[0, 1, 2, 3, 4].extract 2 1 = #[]

  • #[0, 1, 2, 3, 4].extract 2 2 = #[]

  • #[0, 1, 2, 3, 4].extract 2 3 = #[2]

  • #[0, 1, 2, 3, 4].extract 2 4 = #[2, 3]

🔗定义
Array.getD.{u_1} {α : Type u_1} (a : Array α) (i : Nat) (v₀ : α) : α
Array.getD.{u_1} {α : Type u_1} (a : Array α) (i : Nat) (v₀ : α) : α

返回给定索引处的元素,从 0 开始计数。如果索引越界,则返回回退值 v₀

要根据索引是否在范围内返回 Option,请使用 a[i]?。要在索引越界时触发 panic,请使用 a[i]!

示例:

  • #["spring", "summer", "fall", "winter"].getD 2 "never" = "fall"

  • #["spring", "summer", "fall", "winter"].getD 0 "never" = "spring"

  • #["spring", "summer", "fall", "winter"].getD 4 "never" = "never"

🔗定义
Array.uget.{u} {α : Type u} (xs : Array α) (i : USize) (h : i.toNat < xs.size) : α
Array.uget.{u} {α : Type u} (xs : Array α) (i : USize) (h : i.toNat < xs.size) : α

低级索引运算符,与 C 数组读取速度一样快。

这可以避免因拆箱用作索引的 Nat 而产生的开销。

🔗定义
Array.back.{u} {α : Type u} (xs : Array α) (h : 0 < xs.size := by get_elem_tactic) : α
Array.back.{u} {α : Type u} (xs : Array α) (h : 0 < xs.size := by get_elem_tactic) : α

给出数组不为空的证明,返回数组的最后一个元素。

请参阅 Array.back! 了解如果数组为空则触发 panic 的版本,或 Array.back? 了解返回选项的版本。

🔗定义
Array.back?.{u} {α : Type u} (xs : Array α) : Option α
Array.back?.{u} {α : Type u} (xs : Array α) : Option α

返回数组的最后一个元素,如果数组为空,则返回 none

请参阅 Array.back! 了解如果数组为空则触发 panic 的版本,或 Array.back 了解需要证明数组非空的版本。

🔗定义
Array.back!.{u} {α : Type u} [Inhabited α] (xs : Array α) : α
Array.back!.{u} {α : Type u} [Inhabited α] (xs : Array α) : α

返回数组的最后一个元素,如果数组为空,则触发 panic。

更安全的替代方案包括 Array.back(需要证明数组非空)和 Array.back?(返回 Option)。

🔗定义
Array.getMax?.{u} {α : Type u} (as : Array α) (lt : α α Bool) : Option α
Array.getMax?.{u} {α : Type u} (as : Array α) (lt : α α Bool) : Option α

返回数组的最大元素,由比较 lt 确定,如果数组为空,则返回 none

示例:

20.16.4.4. 查询🔗

🔗定义
Array.count.{u} {α : Type u} [BEq α] (a : α) (as : Array α) : Nat
Array.count.{u} {α : Type u} [BEq α] (a : α) (as : Array α) : Nat

计算某个元素在数组中出现的次数。

示例:

  • #[1, 1, 2, 3, 5].count 1 = 2

  • #[1, 1, 2, 3, 5].count 5 = 1

  • #[1, 1, 2, 3, 5].count 4 = 0

🔗定义
Array.countP.{u} {α : Type u} (p : α Bool) (as : Array α) : Nat
Array.countP.{u} {α : Type u} (p : α Bool) (as : Array α) : Nat

计算数组 as 中满足布尔谓词 p 的元素数。

示例:

  • #[1, 2, 3, 4, 5].countP (· % 2 == 0) = 2

  • #[1, 2, 3, 4, 5].countP (· < 5) = 4

  • #[1, 2, 3, 4, 5].countP (· > 5) = 0

🔗定义
Array.idxOf.{u} {α : Type u} [BEq α] (a : α) : Array α Nat
Array.idxOf.{u} {α : Type u} [BEq α] (a : α) : Array α Nat

返回等于 a 的第一个元素的索引,如果没有元素等于 a,则返回数组的大小。

示例:

  • #["carrot", "potato", "broccoli"].idxOf "carrot" = 0

  • #["carrot", "potato", "broccoli"].idxOf "broccoli" = 2

  • #["carrot", "potato", "broccoli"].idxOf "tomato" = 3

  • #["carrot", "potato", "broccoli"].idxOf "anything else" = 3

🔗定义
Array.idxOf?.{u} {α : Type u} [BEq α] (xs : Array α) (v : α) : Option Nat
Array.idxOf?.{u} {α : Type u} [BEq α] (xs : Array α) (v : α) : Option Nat

返回等于 a 的第一个元素的索引,否则返回 none(如果没有元素等于 a)。

示例:

  • #["carrot", "potato", "broccoli"].idxOf? "carrot" = some 0

  • #["carrot", "potato", "broccoli"].idxOf? "broccoli" = some 2

  • #["carrot", "potato", "broccoli"].idxOf? "tomato" = none

  • #["carrot", "potato", "broccoli"].idxOf? "anything else" = none

🔗定义
Array.finIdxOf?.{u} {α : Type u} [BEq α] (xs : Array α) (v : α) : Option (Fin xs.size)
Array.finIdxOf?.{u} {α : Type u} [BEq α] (xs : Array α) (v : α) : Option (Fin xs.size)

返回等于 a 的第一个元素的索引,否则返回 none(如果没有元素等于 a)。该索引以 Fin 形式返回,这保证它在范围内。

示例:

20.16.4.5. 转换🔗

🔗定义
Array.toList.{u} {α : Type u} (self : Array α) : List α
Array.toList.{u} {α : Type u} (self : Array α) : List α

Array α 转换为包含相同顺序的相同元素的 List α

在运行时,这是由 Array.toListImpl 实现的,并且数组的长度为 O(n)

🔗定义
Array.toListRev.{u_1} {α : Type u_1} (xs : Array α) : List α
Array.toListRev.{u_1} {α : Type u_1} (xs : Array α) : List α

将数组转换为包含相同元素但顺序相反的列表。

这相当于 Array.toList List.reverse,但效率更高。

示例:

🔗定义
Array.toListAppend.{u} {α : Type u} (as : Array α) (l : List α) : List α
Array.toListAppend.{u} {α : Type u} (as : Array α) (l : List α) : List α

将数组添加到列表前面。数组的元素位于结果列表的开头。

相当于as.toList ++ l

示例:

🔗定义
Array.toVector.{u_1} {α : Type u_1} (xs : Array α) : Vector α xs.size
Array.toVector.{u_1} {α : Type u_1} (xs : Array α) : Vector α xs.size

将数组转换为向量。结果向量的大小就是数组的大小。

🔗定义
Array.toSubarray.{u} {α : Type u} (as : Array α) (start : Nat := 0) (stop : Nat := as.size) : Subarray α
Array.toSubarray.{u} {α : Type u} (as : Array α) (start : Nat := 0) (stop : Nat := as.size) : Subarray α

返回具有给定边界的数组的子数组。

如果 startstop 不是子数组的有效边界,则它们将被限制为数组的大小。此外,起始索引被限制到结束索引。

🔗定义
Array.ofSubarray.{u} {α : Type u} (s : Subarray α) : Array α
Array.ofSubarray.{u} {α : Type u} (s : Subarray α) : Array α

分配一个包含子数组内容的新数组。

20.16.4.6. 修改🔗

🔗定义
Array.push.{u} {α : Type u} (a : Array α) (v : α) : Array α
Array.push.{u} {α : Type u} (a : Array α) (v : α) : Array α

将一个元素添加到数组的末尾。生成的数组的大小比输入数组大 1。如果没有对该数组的其他引用,则就地修改它。

这需要摊销 O(1) 时间,因为 Array α 由动态数组表示。

示例:

  • #[].push "apple" = #["apple"]

  • #["apple"].push "orange" = #["apple", "orange"]

🔗定义
Array.pop.{u} {α : Type u} (xs : Array α) : Array α
Array.pop.{u} {α : Type u} (xs : Array α) : Array α

删除数组的最后一个元素。如果数组为空,则原样返回。当对数组的引用是唯一的时,修改就地执行。

示例:

🔗定义
Array.popWhile.{u} {α : Type u} (p : α Bool) (as : Array α) : Array α
Array.popWhile.{u} {α : Type u} (p : α Bool) (as : Array α) : Array α

从数组末尾删除满足谓词的所有元素。

删除所有满足谓词的最长连续元素序列。

示例:

🔗定义
Array.erase.{u} {α : Type u} [BEq α] (as : Array α) (a : α) : Array α
Array.erase.{u} {α : Type u} [BEq α] (as : Array α) (a : α) : Array α

从数组中删除第一次出现的指定元素,如果不存在则不执行任何操作。

此函数在最坏情况下需要 O(n) 时间,因为它会向后移动所有后面的元素。

示例:

  • #[1, 2, 3].erase 2 = #[1, 3]

  • #[1, 2, 3].erase 5 = #[1, 2, 3]

  • #[1, 2, 3, 2, 1].erase 2 = #[1, 3, 2, 1]

  • (#[] : List Nat).erase 2 = #[]

🔗定义
Array.eraseP.{u} {α : Type u} (as : Array α) (p : α Bool) : Array α
Array.eraseP.{u} {α : Type u} (as : Array α) (p : α Bool) : Array α

删除第一个满足谓词 p 的元素。如果没有元素满足 p,则返回未修改的数组。

此函数在最坏情况下需要 O(n) 时间,因为它会向后移动所有后面的元素。

示例:

  • #["red", "green", "", "blue"].eraseP (·.isEmpty) = #["red", "green", "blue"]

  • #["red", "green", "", "blue", ""].eraseP (·.isEmpty) = #["red", "green", "blue", ""]

  • #["red", "green", "blue"].eraseP (·.length % 2 == 0) = #["red", "green"]

  • #["red", "green", "blue"].eraseP (fun _ => true) = #["green", "blue"]

  • (#[] : Array String).eraseP (fun _ => true) = #[]

🔗定义
Array.eraseIdx.{u} {α : Type u} (xs : Array α) (i : Nat) (h : i < xs.size := by get_elem_tactic) : Array α
Array.eraseIdx.{u} {α : Type u} (xs : Array α) (i : Nat) (h : i < xs.size := by get_elem_tactic) : Array α

从数组中删除给定索引处的元素,而不进行运行时边界检查。

此函数需要最坏情况下的 O(n) 时间,因为它会将大于 i 的位置处的所有元素后移。

示例:

  • #["apple", "pear", "orange"].eraseIdx 0 = #["pear", "orange"]

  • #["apple", "pear", "orange"].eraseIdx 1 = #["apple", "orange"]

  • #["apple", "pear", "orange"].eraseIdx 2 = #["apple", "pear"]

🔗定义
Array.eraseIdx!.{u} {α : Type u} (xs : Array α) (i : Nat) : Array α
Array.eraseIdx!.{u} {α : Type u} (xs : Array α) (i : Nat) : Array α

从数组中删除给定索引处的元素。如果索引越界,则会触发 panic。

此函数需要最坏情况下的 O(n) 时间,因为它会将大于 i 的位置处的所有元素后移。

🔗定义
Array.eraseIdxIfInBounds.{u} {α : Type u} (xs : Array α) (i : Nat) : Array α
Array.eraseIdxIfInBounds.{u} {α : Type u} (xs : Array α) (i : Nat) : Array α

从数组中删除给定索引处的元素。如果索引越界,则不执行任何操作。

此函数需要最坏情况下的 O(n) 时间,因为它会将大于 i 的位置处的所有元素后移。

示例:

🔗定义
Array.eraseReps.{u_1} {α : Type u_1} [BEq α] (as : Array α) : Array α
Array.eraseReps.{u_1} {α : Type u_1} [BEq α] (as : Array α) : Array α

擦除重复的元素,保留每次运行的第一个元素。

O(|as|)

例子:

  • #[1, 3, 2, 2, 2, 3, 3, 5].eraseReps = #[1, 3, 2, 3, 5]

🔗定义
Array.swap.{u} {α : Type u} (xs : Array α) (i j : Nat) (hi : i < xs.size := by get_elem_tactic) (hj : j < xs.size := by get_elem_tactic) : Array α
Array.swap.{u} {α : Type u} (xs : Array α) (i j : Nat) (hi : i < xs.size := by get_elem_tactic) (hj : j < xs.size := by get_elem_tactic) : Array α

交换数组的两个元素。当对数组的引用是唯一的时,修改就地执行。

示例:

  • #["red", "green", "blue", "brown"].swap 0 3 = #["brown", "green", "blue", "red"]

  • #["red", "green", "blue", "brown"].swap 0 2 = #["blue", "green", "red", "brown"]

  • #["red", "green", "blue", "brown"].swap 1 2 = #["red", "blue", "green", "brown"]

  • #["red", "green", "blue", "brown"].swap 3 0 = #["brown", "green", "blue", "red"]

🔗定义
Array.swapIfInBounds.{u} {α : Type u} (xs : Array α) (i j : Nat) : Array α
Array.swapIfInBounds.{u} {α : Type u} (xs : Array α) (i j : Nat) : Array α

交换数组的两个元素,如果任一索引超出范围,则返回数组不变。当对数组的引用是唯一的时,修改就地执行。

示例:

  • #["red", "green", "blue", "brown"].swapIfInBounds 0 3 = #["brown", "green", "blue", "red"]

  • #["red", "green", "blue", "brown"].swapIfInBounds 0 2 = #["blue", "green", "red", "brown"]

  • #["red", "green", "blue", "brown"].swapIfInBounds 1 2 = #["red", "blue", "green", "brown"]

  • #["red", "green", "blue", "brown"].swapIfInBounds 0 4 = #["red", "green", "blue", "brown"]

  • #["red", "green", "blue", "brown"].swapIfInBounds 9 2 = #["red", "green", "blue", "brown"]

🔗定义
Array.swapAt.{u} {α : Type u} (xs : Array α) (i : Nat) (v : α) (hi : i < xs.size := by get_elem_tactic) : α × Array α
Array.swapAt.{u} {α : Type u} (xs : Array α) (i : Nat) (v : α) (hi : i < xs.size := by get_elem_tactic) : α × Array α

将新元素与给定索引处的元素交换。

返回之前在 i 处找到的值,与一个数组配对,其中 i 处的值已替换为 v

示例:

  • #["spinach", "broccoli", "carrot"].swapAt 1 "pepper" = ("broccoli", #["spinach", "pepper", "carrot"])

  • #["spinach", "broccoli", "carrot"].swapAt 2 "pepper" = ("carrot", #["spinach", "broccoli", "pepper"])

🔗定义
Array.swapAt!.{u} {α : Type u} (xs : Array α) (i : Nat) (v : α) : α × Array α
Array.swapAt!.{u} {α : Type u} (xs : Array α) (i : Nat) (v : α) : α × Array α

将新元素与给定索引处的元素交换。如果索引越界,则会触发 panic。

返回之前在 i 处找到的值,与一个数组配对,其中 i 处的值已替换为 v

示例:

  • #["spinach", "broccoli", "carrot"].swapAt! 1 "pepper" = (#["spinach", "pepper", "carrot"], "broccoli")

  • #["spinach", "broccoli", "carrot"].swapAt! 2 "pepper" = (#["spinach", "broccoli", "pepper"], "carrot")

🔗定义
Array.replace.{u} {α : Type u} [BEq α] (xs : Array α) (a b : α) : Array α
Array.replace.{u} {α : Type u} [BEq α] (xs : Array α) (a b : α) : Array α

将数组中第一次出现的 a 替换为 b。当对数组的引用是唯一的时,修改就地执行。当 a 不存在时,返回未修改的数组。

示例:

  • #[1, 2, 3, 2, 1].replace 2 5 = #[1, 5, 3, 2, 1]

  • #[1, 2, 3, 2, 1].replace 0 5 = #[1, 2, 3, 2, 1]

  • #[].replace 2 5 = #[]

🔗定义
Array.set.{u_1} {α : Type u_1} (xs : Array α) (i : Nat) (v : α) (h : i < xs.size := by get_elem_tactic) : Array α
Array.set.{u_1} {α : Type u_1} (xs : Array α) (i : Nat) (v : α) (h : i < xs.size := by get_elem_tactic) : Array α

替换数组中给定索引处的元素。

不执行边界检查,但该函数需要证明索引在边界内。这个证明通常可以省略,并且会自动合成。

如果没有其他引用,则该数组将被就地修改。

示例:

  • #[0, 1, 2].set 1 5 = #[0, 5, 2]

  • #["orange", "apple"].set 1 "grape" = #["orange", "grape"]

🔗定义
Array.set!.{u_1} {α : Type u_1} (xs : Array α) (i : Nat) (v : α) : Array α
Array.set!.{u_1} {α : Type u_1} (xs : Array α) (i : Nat) (v : α) : Array α

在数组中设置一个元素,或者如果索引越界则触发 panic。

如果调用时 a 的引用计数为 1,这将破坏性地执行更新。

🔗定义
Array.setIfInBounds.{u_1} {α : Type u_1} (xs : Array α) (i : Nat) (v : α) : Array α
Array.setIfInBounds.{u_1} {α : Type u_1} (xs : Array α) (i : Nat) (v : α) : Array α

替换数组中提供的索引处的元素。如果索引越界,则返回未修改的数组。

如果没有其他引用,则该数组将被就地修改。

示例:

🔗定义
Array.uset.{u} {α : Type u} (xs : Array α) (i : USize) (v : α) (h : i.toNat < xs.size) : Array α
Array.uset.{u} {α : Type u} (xs : Array α) (i : USize) (v : α) (h : i.toNat < xs.size) : Array α

低级修改运算符与 C 数组写入一样快。当对数组的引用是唯一的时,修改就地执行。

这可以避免因拆箱用作索引的 Nat 而产生的开销。

🔗定义
Array.modify.{u} {α : Type u} (xs : Array α) (i : Nat) (f : α α) : Array α
Array.modify.{u} {α : Type u} (xs : Array α) (i : Nat) (f : α α) : Array α

将给定索引处的元素(如果存在)替换为对其应用 f 的结果。如果索引无效,则返回未修改的数组。

示例:

  • #[1, 2, 3].modify 0 (· * 10) = #[10, 2, 3]

  • #[1, 2, 3].modify 2 (· * 10) = #[1, 2, 30]

  • #[1, 2, 3].modify 3 (· * 10) = #[1, 2, 3]

🔗定义
Array.modifyM.{u, u_1} {α : Type u} {m : Type u Type u_1} [Monad m] (xs : Array α) (i : Nat) (f : α m α) : m (Array α)
Array.modifyM.{u, u_1} {α : Type u} {m : Type u Type u_1} [Monad m] (xs : Array α) (i : Nat) (f : α m α) : m (Array α)

将给定索引处的元素(如果存在)替换为对其应用一元函数 f 的结果。如果索引无效,则返回未修改的数组,并且不会调用 f

示例:

#[1, 2, 30, 4]It was 3 #eval #[1, 2, 3, 4].modifyM 2 fun x => do IO.println s!"It was {x}" return x * 10 It was 3#[1, 2, 30, 4]#[1, 2, 3, 4]#eval #[1, 2, 3, 4].modifyM 6 fun x => do IO.println s!"It was {x}" return x * 10 #[1, 2, 3, 4]
🔗定义
Array.modifyOp.{u} {α : Type u} (xs : Array α) (idx : Nat) (f : α α) : Array α
Array.modifyOp.{u} {α : Type u} (xs : Array α) (idx : Nat) (f : α α) : Array α

将给定索引处的元素(如果存在)替换为对其应用 f 的结果。如果索引无效,则返回未修改的数组。

示例:

  • #[1, 2, 3].modifyOp 0 (· * 10) = #[10, 2, 3]

  • #[1, 2, 3].modifyOp 2 (· * 10) = #[1, 2, 30]

  • #[1, 2, 3].modifyOp 3 (· * 10) = #[1, 2, 3]

🔗定义
Array.insertIdx.{u} {α : Type u} (as : Array α) (i : Nat) (a : α) : autoParam (i as.size) Array.insertIdx._auto_1 Array α
Array.insertIdx.{u} {α : Type u} (as : Array α) (i : Nat) (a : α) : autoParam (i as.size) Array.insertIdx._auto_1 Array α

将元素插入到数组中指定索引处。如果索引大于数组的大小,则返回未修改的数组。

换句话说,新元素被插入到数组 as 中前 i 个元素之后;此数组即 as

此函数在最坏情况下需要 O(n) 时间,因为它必须将插入的元素交换到位。

示例:

  • #["tues", "thur", "sat"].insertIdx 1 "wed" = #["tues", "wed", "thur", "sat"]

  • #["tues", "thur", "sat"].insertIdx 2 "wed" = #["tues", "thur", "wed", "sat"]

  • #["tues", "thur", "sat"].insertIdx 3 "wed" = #["tues", "thur", "sat", "wed"]

🔗定义
Array.insertIdx!.{u} {α : Type u} (as : Array α) (i : Nat) (a : α) : Array α
Array.insertIdx!.{u} {α : Type u} (as : Array α) (i : Nat) (a : α) : Array α

将元素插入到数组中指定索引处。如果索引大于数组的大小,则会触发 panic。

换句话说,新元素被插入到数组 as 中前 i 个元素之后;此数组即 as

此函数在最坏情况下需要 O(n) 时间,因为它必须将插入的元素交换到位。 Array.insertIdxArray.insertIdxIfInBounds 是更安全的替代品。

示例:

  • #["tues", "thur", "sat"].insertIdx! 1 "wed" = #["tues", "wed", "thur", "sat"]

  • #["tues", "thur", "sat"].insertIdx! 2 "wed" = #["tues", "thur", "wed", "sat"]

  • #["tues", "thur", "sat"].insertIdx! 3 "wed" = #["tues", "thur", "sat", "wed"]

🔗定义
Array.insertIdxIfInBounds.{u} {α : Type u} (as : Array α) (i : Nat) (a : α) : Array α
Array.insertIdxIfInBounds.{u} {α : Type u} (as : Array α) (i : Nat) (a : α) : Array α

将元素插入到数组中指定索引处。如果索引大于数组的大小,则返回未修改的数组。

换句话说,新元素被插入到数组 as 中前 i 个元素之后;此数组即 as

此函数在最坏情况下需要 O(n) 时间,因为它必须将插入的元素交换到位。

示例:

🔗定义
Array.reverse.{u} {α : Type u} (as : Array α) : Array α
Array.reverse.{u} {α : Type u} (as : Array α) : Array α

通过重复交换元素来反转数组。

如果没有其他引用,则原数组将被就地修改。

示例:

🔗定义
Array.take.{u} {α : Type u} (xs : Array α) (i : Nat) : Array α
Array.take.{u} {α : Type u} (xs : Array α) (i : Nat) : Array α

返回一个新数组,其中包含前 i 个元素,这些元素取自 xs。如果 xs 的元素少于 i 的元素,则新数组包含 xs 的所有元素。

返回的数组始终是一个新数组,即使它包含与输入数组相同的元素。

示例:

  • #["red", "green", "blue"].take 1 = #["red"]

  • #["red", "green", "blue"].take 2 = #["red", "green"]

  • #["red", "green", "blue"].take 5 = #["red", "green", "blue"]

🔗定义
Array.takeWhile.{u} {α : Type u} (p : α Bool) (as : Array α) : Array α
Array.takeWhile.{u} {α : Type u} (p : α Bool) (as : Array α) : Array α

返回一个新数组,其中包含数组中满足谓词 p 的元素的最长前缀。

示例:

  • #[0, 1, 2, 3, 2, 1].takeWhile (· < 2) = #[0, 1]

  • #[0, 1, 2, 3, 2, 1].takeWhile (· < 20) = #[0, 1, 2, 3, 2, 1]

  • #[0, 1, 2, 3, 2, 1].takeWhile (· < 0) = #[]

🔗定义
Array.drop.{u} {α : Type u} (xs : Array α) (i : Nat) : Array α
Array.drop.{u} {α : Type u} (xs : Array α) (i : Nat) : Array α

删除前 i 个元素,这些元素取自 xs。如果 xs 的元素少于 i 的元素,则新数组为空。

返回的数组始终是一个新数组,即使它包含与输入数组相同的元素。

示例:

  • #["red", "green", "blue"].drop 1 = #["green", "blue"]

  • #["red", "green", "blue"].drop 2 = #["blue"]

  • #["red", "green", "blue"].drop 5 = #[]

🔗定义
Array.shrink.{u} {α : Type u} (xs : Array α) (n : Nat) : Array α
Array.shrink.{u} {α : Type u} (xs : Array α) (n : Nat) : Array α

返回数组的前 n 元素。结果数组是通过重复调用 Array.pop 生成的。如果 n 大于数组的大小,则原样返回。

如果对数组的引用是唯一的,则此函数使用就地修改。

示例:

  • #[0, 1, 2, 3, 4].shrink 2 = #[0, 1]

  • #[0, 1, 2, 3, 4].shrink 0 = #[]

  • #[0, 1, 2, 3, 4].shrink 10 = #[0, 1, 2, 3, 4]

🔗定义
Array.flatten.{u} {α : Type u} (xss : Array (Array α)) : Array α
Array.flatten.{u} {α : Type u} (xss : Array (Array α)) : Array α

将数组数组的内容追加到单个数组中。生成的数组包含与嵌套数组相同的元素,并且顺序相同。

示例:

🔗定义
Array.getEvenElems.{u} {α : Type u} (as : Array α) : Array α
Array.getEvenElems.{u} {α : Type u} (as : Array α) : Array α

返回一个新数组,其中包含 as 中偶数索引处的元素,从索引 0 处的元素开始。

示例:

20.16.4.7. 有序数组🔗

🔗定义
Array.qsort.{u_1} {α : Type u_1} (as : Array α) (lt : α α Bool := by exact < ·)) (lo : Nat := 0) (hi : Nat := as.size - 1) : Array α
Array.qsort.{u_1} {α : Type u_1} (as : Array α) (lt : α α Bool := by exact < ·)) (lo : Nat := 0) (hi : Nat := as.size - 1) : Array α

就地快速排序。

qsort as lt lo hi 对子数组 as[lo...=hi] 进行就地排序,并使用 lt 比较元素。

🔗定义
Array.qsortOrd.{u_1} {α : Type u_1} [ord : Ord α] (xs : Array α) : Array α
Array.qsortOrd.{u_1} {α : Type u_1} [ord : Ord α] (xs : Array α) : Array α

使用 compare 对数组进行排序以比较元素。

🔗定义
Array.insertionSort.{u_1} {α : Type u_1} (xs : Array α) (lt : α α Bool := by exact < ·)) : Array α
Array.insertionSort.{u_1} {α : Type u_1} (xs : Array α) (lt : α α Bool := by exact < ·)) : Array α

使用插入排序对数组进行排序。

可选参数 lt 指定排序谓词。它默认为 LT.lt,它必须是可判定的才能用于排序。

🔗定义
Array.binInsert.{u} {α : Type u} (lt : α α Bool) (as : Array α) (k : α) : Array α
Array.binInsert.{u} {α : Type u} (lt : α α Bool) (as : Array α) (k : α) : Array α

将一个元素插入到已排序的数组中,以便对结果数组进行排序。如果该元素已存在于数组中,则不会插入该元素。

排序谓词 lt 应该是元素的总顺序,并且数组 as 应相对于 lt 进行排序。

Array.binInsertM 是一个更通用的运算符,除了在 monad 中运行之外,还可以更好地控制重复元素的处理。

示例:

  • #[0, 1, 3, 5].binInsert (· < ·) 2 = #[0, 1, 2, 3, 5]

  • #[0, 1, 3, 5].binInsert (· < ·) 1 = #[0, 1, 3, 5]

  • #[].binInsert (· < ·) 1 = #[1]

🔗定义
Array.binInsertM.{u, v} {α : Type u} {m : Type u Type v} [Monad m] (lt : α α Bool) (merge : α m α) (add : Unit m α) (as : Array α) (k : α) : m (Array α)
Array.binInsertM.{u, v} {α : Type u} {m : Type u Type v} [Monad m] (lt : α α Bool) (merge : α m α) (add : Unit m α) (as : Array α) (k : α) : m (Array α)

将元素 k 插入已排序数组 as 中,以便对结果数组进行排序。

排序谓词 lt 应该是元素的总顺序,并且数组 as 应相对于 lt 进行排序。

如果 lt 等于 k 的元素已存在于 as 中,则 merge 将应用于现有元素以确定结果数组中该位置的值。如果不存在等于 k 的元素,则使用 add 来确定要插入的值。

🔗定义
Array.binSearch {α : Type} (as : Array α) (k : α) (lt : α α Bool) (lo : Nat := 0) (hi : Nat := as.size - 1) : Option α
Array.binSearch {α : Type} (as : Array α) (k : α) (lt : α α Bool) (lo : Nat := 0) (hi : Nat := as.size - 1) : Option α

二分查找与 k 等效的元素,搜索对象是排序数组 as。如果找到,则返回数组中的元素,否则返回 none

数组as必须根据比较运算符lt进行排序,这应该是全序。

可选参数 lohi 确定要搜索的数组索引的区域。两者都是包容性的,并且默认搜索整个数组。

🔗定义
Array.binSearchContains {α : Type} (as : Array α) (k : α) (lt : α α Bool) (lo : Nat := 0) (hi : Nat := as.size - 1) : Bool
Array.binSearchContains {α : Type} (as : Array α) (k : α) (lt : α α Bool) (lo : Nat := 0) (hi : Nat := as.size - 1) : Bool

二分查找与 k 等效的元素,搜索对象是排序数组 as。如果找到该元素,则返回 true,否则返回 false

数组as必须根据比较运算符lt进行排序,这应该是全序。

可选参数 lohi 确定要搜索的数组索引的区域。两者都是包容性的,并且默认搜索整个数组。

20.16.4.8. 迭代🔗

🔗定义
Array.iter.{w} {α : Type w} (l : Array α) : Std.Iter α
Array.iter.{w} {α : Type w} (l : Array α) : Std.Iter α

返回给定数组的有限迭代器。迭代器按顺序生成数组的元素,然后终止。

该迭代器的单子版本是 Array.iterM

终止属性:

  • Finite 实例:始终

  • Productive 实例:始终

🔗定义
Array.iterFromIdx.{w} {α : Type w} (l : Array α) (pos : Nat) : Std.Iter α
Array.iterFromIdx.{w} {α : Type w} (l : Array α) (pos : Nat) : Std.Iter α

返回从给定索引开始的给定数组的有限迭代器。迭代器按顺序生成数组的元素,然后终止。

该迭代器的单子版本是 Array.iterFromIdxM

终止属性:

  • Finite 实例:始终

  • Productive 实例:始终

🔗定义
Array.iterM.{w, w'} {α : Type w} (array : Array α) (m : Type w Type w') [Pure m] : Std.IterM m α
Array.iterM.{w, w'} {α : Type w} (array : Array α) (m : Type w Type w') [Pure m] : Std.IterM m α

返回给定数组的有限一元迭代器。迭代器按顺序生成数组的元素,然后终止。没有副作用。

该迭代器的纯净版本是Array.iter

终止属性:

  • Finite 实例:始终

  • Productive 实例:始终

🔗定义
Array.iterFromIdxM.{w, w'} {α : Type w} (array : Array α) (m : Type w Type w') (pos : Nat) [Pure m] : Std.IterM m α
Array.iterFromIdxM.{w, w'} {α : Type w} (array : Array α) (m : Type w Type w') (pos : Nat) [Pure m] : Std.IterM m α

返回从给定索引开始的给定数组的有限一元迭代器。迭代器按顺序生成数组的元素,然后终止。

该迭代器的纯净版本是Array.iterFromIdx

终止属性:

  • Finite 实例:始终

  • Productive 实例:始终

🔗定义
Array.foldr.{u, v} {α : Type u} {β : Type v} (f : α β β) (init : β) (as : Array α) (start : Nat := as.size) (stop : Nat := 0) : β
Array.foldr.{u, v} {α : Type u} {β : Type v} (f : α β β) (init : β) (as : Array α) (start : Nat := as.size) (stop : Nat := 0) : β

从右侧将函数折叠到数组上,累加以 init 开头的值。使用 f 将累加值与数组的每个元素按相反顺序组合。

可选参数 startstop 控制要折叠的阵列区域。折叠从start(不包括)到stop(包括)进行,因此除非start > stop,否则不会发生折叠。默认情况下,使用整个数组。

示例:

  • #[a, b, c].foldr f init = f a (f b (f c init))

  • #[1, 2, 3].foldr (toString · ++ ·) "" = "123"

  • #[1, 2, 3].foldr (s!"({·} {·})") "!" = "(1 (2 (3 !)))"

🔗定义
Array.foldrM.{u, v, w} {α : Type u} {β : Type v} {m : Type v Type w} [Monad m] (f : α β m β) (init : β) (as : Array α) (start : Nat := as.size) (stop : Nat := 0) : m β
Array.foldrM.{u, v, w} {α : Type u} {β : Type v} {m : Type v Type w} [Monad m] (f : α β m β) (init : β) (as : Array α) (start : Nat := as.size) (stop : Nat := 0) : m β

从右侧开始在数组上折叠一元函数,累积以 init 开头的值。使用 f 将累积值与列表中的每个元素按相反顺序组合。

可选参数 startstop 控制要折叠的阵列区域。折叠从start(不包括)到stop(包括)进行,因此除非start > stop,否则不会发生折叠。默认情况下,整个数组是折叠的。

示例:

example [Monad m] (f : α → β → m β) :
  Array.foldrM (m := m) f x₀ #[a, b, c] = (do
    let x₁ ← f c x₀
    let x₂ ← f b x₁
    let x₃ ← f a x₂
    pure x₃)
  := by rfl
example [Monad m] (f : α → β → m β) :
  Array.foldrM (m := m) f x₀ #[a, b, c] (start := 2) = (do
    let x₁ ← f b x₀
    let x₂ ← f a x₁
    pure x₂)
  := by rfl
🔗定义
Array.foldl.{u, v} {α : Type u} {β : Type v} (f : β α β) (init : β) (as : Array α) (start : Nat := 0) (stop : Nat := as.size) : β
Array.foldl.{u, v} {α : Type u} {β : Type v} (f : β α β) (init : β) (as : Array α) (start : Nat := 0) (stop : Nat := as.size) : β

从左侧折叠数组上的函数,累加以 init 开头的值。使用 f 将累加值按顺序与数组的每个元素组合。

可选参数 startstop 控制要折叠的阵列区域。折叠从start(包含)到stop(不包含)进行,因此除非start < stop,否则不会发生折叠。默认情况下,使用整个数组。

示例:

  • #[a, b, c].foldl f z = f (f (f z a) b) c

  • #[1, 2, 3].foldl (· ++ toString ·) "" = "123"

  • #[1, 2, 3].foldl (s!"({·} {·})") "" = "((( 1) 2) 3)"

🔗定义
Array.foldlM.{u, v, w} {α : Type u} {β : Type v} {m : Type v Type w} [Monad m] (f : β α m β) (init : β) (as : Array α) (start : Nat := 0) (stop : Nat := as.size) : m β
Array.foldlM.{u, v, w} {α : Type u} {β : Type v} {m : Type v Type w} [Monad m] (f : β α m β) (init : β) (as : Array α) (start : Nat := 0) (stop : Nat := as.size) : m β

将一元函数从左侧折叠到列表上,累积以 init 开头的值。使用 f 将累加值按顺序与列表中的每个元素组合。

可选参数 startstop 控制要折叠的阵列区域。折叠从start(包含)到stop(不包含)进行,因此除非start < stop,否则不会发生折叠。默认情况下,整个数组是折叠的。

示例:

example [Monad m] (f : α → β → m α) :
    Array.foldlM (m := m) f x₀ #[a, b, c] = (do
      let x₁ ← f x₀ a
      let x₂ ← f x₁ b
      let x₃ ← f x₂ c
      pure x₃)
  := by rfl
example [Monad m] (f : α → β → m α) :
    Array.foldlM (m := m) f x₀ #[a, b, c] (start := 1) = (do
      let x₁ ← f x₀ b
      let x₂ ← f x₁ c
      pure x₂)
  := by rfl
🔗定义
Array.forM.{u, v, w} {α : Type u} {m : Type v Type w} [Monad m] (f : α m PUnit) (as : Array α) (start : Nat := 0) (stop : Nat := as.size) : m PUnit
Array.forM.{u, v, w} {α : Type u} {m : Type v Type w} [Monad m] (f : α m PUnit) (as : Array α) (start : Nat := 0) (stop : Nat := as.size) : m PUnit

按顺序将一元操作 f 应用于数组的每个元素。

可选参数 startstop 控制应应用 f 的数组区域。迭代从start(包含)到stop(不包含)进行,因此不会调用f,除非start < stop。默认情况下,使用整个数组。

🔗定义
Array.forRevM.{u, v, w} {α : Type u} {m : Type v Type w} [Monad m] (f : α m PUnit) (as : Array α) (start : Nat := as.size) (stop : Nat := 0) : m PUnit
Array.forRevM.{u, v, w} {α : Type u} {m : Type v Type w} [Monad m] (f : α m PUnit) (as : Array α) (start : Nat := as.size) (stop : Nat := 0) : m PUnit

以相反的顺序从右到左将一元操作 f 应用于数组的每个元素。

可选参数 startstop 控制应应用 f 的数组区域。迭代从start(不包括)到stop(包括),因此不会调用f,除非start > stop。默认情况下,使用整个数组。

🔗定义
Array.firstM.{u, v, w} {β : Type v} {α : Type u} {m : Type v Type w} [Alternative m] (f : α m β) (as : Array α) : m β
Array.firstM.{u, v, w} {β : Type v} {α : Type u} {m : Type v Type w} [Alternative m] (f : α m β) (as : Array α) : m β

在阵列上映射 f 并使用 <|> 收集结果。数组末尾的结果是 failure

示例:

🔗定义
Array.sum.{u_1} {α : Type u_1} [Add α] [Zero α] : Array α α
Array.sum.{u_1} {α : Type u_1} [Add α] [Zero α] : Array α α

计算数组元素的总和。

示例:

  • #[a, b, c].sum = a + (b + (c + 0))

  • #[1, 2, 5].sum = 8

20.16.4.9. 变换🔗

🔗定义
Array.map.{u, v} {α : Type u} {β : Type v} (f : α β) (as : Array α) : Array β
Array.map.{u, v} {α : Type u} {β : Type v} (f : α β) (as : Array α) : Array β

将函数应用于数组的每个元素,返回结果值数组。

示例:

  • #[a, b, c].map f = #[f a, f b, f c]

  • #[].map Nat.succ = #[]

  • #["one", "two", "three"].map (·.length) = #[3, 3, 5]

  • #["one", "two", "three"].map (·.reverse) = #["eno", "owt", "eerht"]

🔗定义
Array.mapMono.{u_1} {α : Type u_1} (as : Array α) (f : α α) : Array α
Array.mapMono.{u_1} {α : Type u_1} (as : Array α) (f : α α) : Array α

将函数应用于数组的每个元素,返回结果数组。该函数是单态的:要求返回相同类型的值。内部实现使用指针相等,并且如果每个函数调用的结果与其参数指针相等,则不会分配新数组。

🔗定义
Array.mapM.{u, v, w} {α : Type u} {β : Type v} {m : Type v Type w} [Monad m] (f : α m β) (as : Array α) : m (Array β)
Array.mapM.{u, v, w} {α : Type u} {β : Type v} {m : Type v Type w} [Monad m] (f : α m β) (as : Array α) : m (Array β)

将一元操作 f 从左到右应用于数组中的每个元素,并返回结果数组。

🔗定义
Array.mapM'.{u_1, u_2, u_3} {m : Type u_1 Type u_2} {α : Type u_3} {β : Type u_1} [Monad m] (f : α m β) (as : Array α) : m { bs // bs.size = as.size }
Array.mapM'.{u_1, u_2, u_3} {m : Type u_1 Type u_2} {α : Type u_3} {β : Type u_1} [Monad m] (f : α m β) (as : Array α) : m { bs // bs.size = as.size }

将一元操作 f 从左到右应用于数组中的每个元素,并返回结果数组。此外,结果数组的类型保证它包含与输入数组相同数量的元素。

🔗定义
Array.mapMonoM.{u_1, u_2} {m : Type u_1 Type u_2} {α : Type u_1} [Monad m] (as : Array α) (f : α m α) : m (Array α)
Array.mapMonoM.{u_1, u_2} {m : Type u_1 Type u_2} {α : Type u_1} [Monad m] (as : Array α) (f : α m α) : m (Array α)

将一元函数应用于数组的每个元素,返回结果数组。该函数是单态的:要求返回相同类型的值。内部实现使用指针相等,并且如果每个函数调用的结果与其参数指针相等,则不会分配新数组。

🔗定义
Array.mapIdx.{u, v} {α : Type u} {β : Type v} (f : Nat α β) (as : Array α) : Array β
Array.mapIdx.{u, v} {α : Type u} {β : Type v} (f : Nat α β) (as : Array α) : Array β

将函数应用于数组的每个元素以及找到该元素的索引,返回结果数组。

Array.mapFinIdx 是一个变体,它另外为该函数提供索引有效的证明。

🔗定义
Array.mapIdxM.{u, v, w} {α : Type u} {β : Type v} {m : Type v Type w} [Monad m] (f : Nat α m β) (as : Array α) : m (Array β)
Array.mapIdxM.{u, v, w} {α : Type u} {β : Type v} {m : Type v Type w} [Monad m] (f : Nat α m β) (as : Array α) : m (Array β)

将一元操作 f 从左到右应用于数组中的每个元素以及元素的索引。返回结果数组。

🔗定义
Array.mapFinIdx.{u, v} {α : Type u} {β : Type v} (as : Array α) (f : (i : Nat) α i < as.size β) : Array β
Array.mapFinIdx.{u, v} {α : Type u} {β : Type v} (as : Array α) (f : (i : Nat) α i < as.size β) : Array β

将函数应用于数组的每个元素以及找到该元素的索引,返回结果数组。除了索引之外,该函数还提供了索引有效的证明。

Array.mapIdx 是一个变体,它不向函数提供索引有效的证据。

🔗定义
Array.mapFinIdxM.{u, v, w} {α : Type u} {β : Type v} {m : Type v Type w} [Monad m] (as : Array α) (f : (i : Nat) α i < as.size m β) : m (Array β)
Array.mapFinIdxM.{u, v, w} {α : Type u} {β : Type v} {m : Type v Type w} [Monad m] (as : Array α) (f : (i : Nat) α i < as.size m β) : m (Array β)

将一元操作 f 应用于数组中的每个元素,以及元素的索引和索引在边界内的证明(从左到右)。返回结果数组。

🔗定义
Array.flatMap.{u, u_1} {α : Type u} {β : Type u_1} (f : α Array β) (as : Array α) : Array β
Array.flatMap.{u, u_1} {α : Type u} {β : Type u_1} (f : α Array β) (as : Array α) : Array β

应用一个将数组返回到数组的每个元素的函数。附加结果数组。

示例:

🔗定义
Array.flatMapM.{u, u_1, u_2} {α : Type u} {m : Type u_1 Type u_2} {β : Type u_1} [Monad m] (f : α m (Array β)) (as : Array α) : m (Array β)
Array.flatMapM.{u, u_1, u_2} {α : Type u} {m : Type u_1 Type u_2} {β : Type u_1} [Monad m] (f : α m (Array β)) (as : Array α) : m (Array β)

应用一个单子函数,该函数从左到右将数组返回到数组的每个元素。附加结果数组。

🔗定义
Array.zip.{u, u_1} {α : Type u} {β : Type u_1} (as : Array α) (bs : Array β) : Array (α × β)
Array.zip.{u, u_1} {α : Type u} {β : Type u_1} (as : Array α) (bs : Array β) : Array (α × β)

将两个数组组合成一个成对的数组,其中第一个和第二个组件是每个输入数组的对应元素。结果数组是输入数组中较短者的长度。

示例:

  • #["Mon", "Tue", "Wed"].zip #[1, 2, 3] = #[("Mon", 1), ("Tue", 2), ("Wed", 3)]

  • #["Mon", "Tue", "Wed"].zip #[1, 2] = #[("Mon", 1), ("Tue", 2)]

  • #[x₁, x₂, x₃].zip #[y₁, y₂, y₃, y₄] = #[(x₁, y₁), (x₂, y₂), (x₃, y₃)]

🔗定义
Array.zipWith.{u, u_1, u_2} {α : Type u} {β : Type u_1} {γ : Type u_2} (f : α β γ) (as : Array α) (bs : Array β) : Array γ
Array.zipWith.{u, u_1, u_2} {α : Type u} {β : Type u_1} {γ : Type u_2} (f : α β γ) (as : Array α) (bs : Array β) : Array γ

将函数应用于两个数组的相应元素,并在较短数组的末尾停止。

示例:

  • #[1, 2].zipWith (· + ·) #[5, 6] = #[6, 8]

  • #[1, 2, 3].zipWith (· + ·) #[5, 6, 10] = #[6, 8, 13]

  • #[].zipWith (· + ·) #[5, 6] = #[]

  • #[x₁, x₂, x₃].zipWith f #[y₁, y₂, y₃, y₄] = #[f x₁ y₁, f x₂ y₂, f x₃ y₃]

🔗定义
Array.zipWithAll.{u, u_1, u_2} {α : Type u} {β : Type u_1} {γ : Type u_2} (f : Option α Option β γ) (as : Array α) (bs : Array β) : Array γ
Array.zipWithAll.{u, u_1, u_2} {α : Type u} {β : Type u_1} {γ : Type u_2} (f : Option α Option β γ) (as : Array α) (bs : Array β) : Array γ

将函数应用于两个数组的相应元素,当两个数组中都没有更多元素时停止。如果一个数组比另一个数组短,则函数将通过 none 查找缺失的元素。

示例:

🔗定义
Array.zipIdx.{u} {α : Type u} (xs : Array α) (start : Nat := 0) : Array (α × Nat)
Array.zipIdx.{u} {α : Type u} (xs : Array α) (start : Nat := 0) : Array (α × Nat)

将数组的每个元素与其索引配对,可以选择从 0 以外的索引开始。

示例:

  • #[a, b, c].zipIdx = #[(a, 0), (b, 1), (c, 2)]

  • #[a, b, c].zipIdx 5 = #[(a, 5), (b, 6), (c, 7)]

🔗定义
Array.unzip.{u, u_1} {α : Type u} {β : Type u_1} (as : Array (α × β)) : Array α × Array β
Array.unzip.{u, u_1} {α : Type u} {β : Type u_1} (as : Array (α × β)) : Array α × Array β

将数组对分成两个数组,分别包含第一个和第二个组件。

示例:

  • #[("Monday", 1), ("Tuesday", 2)].unzip = (#["Monday", "Tuesday"], #[1, 2])

  • #[(x₁, y₁), (x₂, y₂), (x₃, y₃)].unzip = (#[x₁, x₂, x₃], #[y₁, y₂, y₃])

  • (#[] : Array (Nat × String)).unzip = ((#[], #[]) : List Nat × List String)

20.16.4.10. 过滤🔗

🔗定义
Array.filter.{u} {α : Type u} (p : α Bool) (as : Array α) (start : Nat := 0) (stop : Nat := as.size) : Array α
Array.filter.{u} {α : Type u} (p : α Bool) (as : Array α) (start : Nat := 0) (stop : Nat := as.size) : Array α

返回 as 中的元素数组,其中 p 返回 true

仅考虑从 start(含)到 stop(不含)的元素。该范围之外的元素将被丢弃。默认情况下,考虑整个数组。

示例:

  • #[1, 2, 5, 2, 7, 7].filter (· > 2) = #[5, 7, 7]

  • #[1, 2, 5, 2, 7, 7].filter (fun _ => false) = #[]

  • #[1, 2, 5, 2, 7, 7].filter (fun _ => true) = #[1, 2, 5, 2, 7, 7]

  • #[1, 2, 5, 2, 7, 7].filter (· > 2) (start := 3) = #[7, 7]

  • #[1, 2, 5, 2, 7, 7].filter (fun _ => true) (start := 3) = #[2, 7, 7]

  • #[1, 2, 5, 2, 7, 7].filter (fun _ => true) (stop := 3) = #[1, 2, 5]

🔗定义
Array.filterM.{u_1} {m : Type Type u_1} {α : Type} [Monad m] (p : α m Bool) (as : Array α) (start : Nat := 0) (stop : Nat := as.size) : m (Array α)
Array.filterM.{u_1} {m : Type Type u_1} {α : Type} [Monad m] (p : α m Bool) (as : Array α) (start : Nat := 0) (stop : Nat := as.size) : m (Array α)

按从左到右的顺序将一元谓词 p 应用于数组中的每个元素,并返回 p 返回 true 的元素数组。

仅考虑从 start(含)到 stop(不含)的元素。该范围之外的元素将被丢弃。默认情况下,检查整个数组。

例子:

#[1, 2, 2]Checking 1 Checking 2 Checking 5 Checking 2 Checking 7 Checking 7 #eval #[1, 2, 5, 2, 7, 7].filterM fun x => do IO.println s!"Checking {x}" return x < 3 Checking 1 Checking 2 Checking 5 Checking 2 Checking 7 Checking 7#[1, 2, 2]
🔗定义
Array.filterRevM.{u_1} {m : Type Type u_1} {α : Type} [Monad m] (p : α m Bool) (as : Array α) (start : Nat := as.size) (stop : Nat := 0) : m (Array α)
Array.filterRevM.{u_1} {m : Type Type u_1} {α : Type} [Monad m] (p : α m Bool) (as : Array α) (start : Nat := as.size) (stop : Nat := 0) : m (Array α)

以相反的顺序(从右到左)对数组中的每个元素应用一元谓词 p,并返回 p 返回 true 的那些元素。返回列表中元素的顺序与输入列表中的顺序相同。

仅考虑从 start(不包括)到 stop(包括)的元素。该范围之外的元素将被丢弃。由于按相反顺序检查数组,因此仅在 start > stop 时检查元素。默认情况下,考虑整个数组。

例子:

#[1, 2, 2]Checking 7 Checking 7 Checking 2 Checking 5 Checking 2 Checking 1 #eval #[1, 2, 5, 2, 7, 7].filterRevM fun x => do IO.println s!"Checking {x}" return x < 3 Checking 7 Checking 7 Checking 2 Checking 5 Checking 2 Checking 1#[1, 2, 2]
🔗定义
Array.filterMap.{u, u_1} {α : Type u} {β : Type u_1} (f : α Option β) (as : Array α) (start : Nat := 0) (stop : Nat := as.size) : Array β
Array.filterMap.{u, u_1} {α : Type u} {β : Type u_1} (f : α Option β) (as : Array α) (start : Nat := 0) (stop : Nat := as.size) : Array β

应用向数组的每个元素返回 Option 的函数,收集非 none 值。

例子:

#[10, 14, 14]#eval #[1, 2, 5, 2, 7, 7].filterMap fun x => if x > 2 then some (2 * x) else none #[10, 14, 14]
🔗定义
Array.filterMapM.{u, u_1, u_2} {α : Type u} {m : Type u_1 Type u_2} {β : Type u_1} [Monad m] (f : α m (Option β)) (as : Array α) (start : Nat := 0) (stop : Nat := as.size) : m (Array β)
Array.filterMapM.{u, u_1, u_2} {α : Type u} {m : Type u_1 Type u_2} {β : Type u_1} [Monad m] (f : α m (Option β)) (as : Array α) (start : Nat := 0) (stop : Nat := as.size) : m (Array β)

应用一元函数,该函数将 Option 返回到数组的每个元素,并收集非 none 值。

仅考虑从 start(含)到 stop(不含)的元素。该范围之外的元素将被丢弃。默认情况下,考虑整个数组。

例子:

#[10, 14, 14]Examining 1 Examining 2 Examining 5 Examining 2 Examining 7 Examining 7 #eval #[1, 2, 5, 2, 7, 7].filterMapM fun x => do IO.println s!"Examining {x}" if x > 2 then return some (2 * x) else return none Examining 1 Examining 2 Examining 5 Examining 2 Examining 7 Examining 7#[10, 14, 14]
🔗定义

过滤语法数组,将所有其他元素视为分隔符,而不是使用谓词 p 进行测试的元素。生成的数组包含 p 返回 true 的测试元素,并由相应的分隔符元素分隔。

🔗定义
Array.filterSepElemsM {m : Type Type} [Monad m] (a : Array Lean.Syntax) (p : Lean.Syntax m Bool) : m (Array Lean.Syntax)
Array.filterSepElemsM {m : Type Type} [Monad m] (a : Array Lean.Syntax) (p : Lean.Syntax m Bool) : m (Array Lean.Syntax)

过滤语法数组,将所有其他元素视为分隔符,而不是使用一元谓词 p 进行测试的元素。生成的数组包含 p 返回 true 的测试元素,并由相应的分隔符元素分隔。

20.16.4.11. 分割🔗

🔗定义
Array.partition.{u} {α : Type u} (p : α Bool) (as : Array α) : Array α × Array α
Array.partition.{u} {α : Type u} (p : α Bool) (as : Array α) : Array α × Array α

返回一对数组,它们一起包含 as 的所有元素。第一个数组包含 p 返回 true 的元素,第二个数组包含 p 返回 false 的元素。

as.partition p(as.filter p, as.filter (not p)) 等效,但效率更高,因为它只需对数组执行一次传递。

示例:

  • #[1, 2, 5, 2, 7, 7].partition (· > 2) = (#[5, 7, 7], #[1, 2, 2])

  • #[1, 2, 5, 2, 7, 7].partition (fun _ => false) = (#[], #[1, 2, 5, 2, 7, 7])

  • #[1, 2, 5, 2, 7, 7].partition (fun _ => true) = (#[1, 2, 5, 2, 7, 7], #[])

🔗定义
Array.groupByKey.{u, v} {α : Type u} {β : Type v} [BEq α] [Hashable α] (key : β α) (xs : Array β) : Std.HashMap α (Array β)
Array.groupByKey.{u, v} {α : Type u} {β : Type v} [BEq α] [Hashable α] (key : β α) (xs : Array β) : Std.HashMap α (Array β)

对数组 xs 的元素按函数 key 分组,返回一个哈希映射,其中每个组与其键相关联。组保留 xs 中元素的相对顺序。

例子:

Std.HashMap.ofList [(0, #[0, 2, 4, 6]), (1, #[1, 3, 5])]#eval #[0, 1, 2, 3, 4, 5, 6].groupByKey (· % 2) Std.HashMap.ofList [(0, #[0, 2, 4, 6]), (1, #[1, 3, 5])]

20.16.4.12. 元素判定🔗

🔗定义
Array.contains.{u} {α : Type u} [BEq α] (as : Array α) (a : α) : Bool
Array.contains.{u} {α : Type u} [BEq α] (as : Array α) (a : α) : Bool

检查 a 是否是 as 的元素,使用 == 进行元素比较。

Array.elem 是一个同义词,它采用数组之前的元素。

示例:

🔗定义
Array.elem.{u} {α : Type u} [BEq α] (a : α) (as : Array α) : Bool
Array.elem.{u} {α : Type u} [BEq α] (a : α) (as : Array α) : Bool

检查 a 是否是 as 的元素,使用 == 进行元素比较。

Array.contains 是一个同义词,它将数组放在元素之前。

出于验证目的,Array.elem 简化为 Array.contains

例子:

🔗定义
Array.find?.{u} {α : Type u} (p : α Bool) (as : Array α) : Option α
Array.find?.{u} {α : Type u} (p : α Bool) (as : Array α) : Option α

返回谓词 p 返回 true 的数组的第一个元素,如果未找到此类元素,则返回 none

示例:

  • #[7, 6, 5, 8, 1, 2, 6].find? (· < 5) = some 1

  • #[7, 6, 5, 8, 1, 2, 6].find? (· < 1) = none

🔗定义
Array.findRev? {α : Type} (p : α Bool) (as : Array α) : Option α
Array.findRev? {α : Type} (p : α Bool) (as : Array α) : Option α

返回谓词 p 返回 true 的数组的最后一个元素,如果未找到此类元素,则返回 none

示例:

🔗定义
Array.findIdx.{u} {α : Type u} (p : α Bool) (as : Array α) : Nat
Array.findIdx.{u} {α : Type u} (p : α Bool) (as : Array α) : Nat

返回 p 返回 true 的第一个元素的索引,如果没有这样的元素,则返回数组的大小。

示例:

  • #[7, 6, 5, 8, 1, 2, 6].findIdx (· < 5) = 4

  • #[7, 6, 5, 8, 1, 2, 6].findIdx (· < 1) = 7

🔗定义
Array.findIdx?.{u} {α : Type u} (p : α Bool) (as : Array α) : Option Nat
Array.findIdx?.{u} {α : Type u} (p : α Bool) (as : Array α) : Option Nat

返回 p 返回 true 的第一个元素的索引,如果没有这样的元素,则返回 none

示例:

🔗定义
Array.findIdxM?.{u, u_1} {α : Type u} {m : Type Type u_1} [Monad m] (p : α m Bool) (as : Array α) : m (Option Nat)
Array.findIdxM?.{u, u_1} {α : Type u} {m : Type Type u_1} [Monad m] (p : α m Bool) (as : Array α) : m (Option Nat)

查找一元谓词 p 返回 true 的数组的第一个元素的索引。按从左到右的顺序检查元素,当找到满足 p 的元素时终止搜索。如果数组中不存在这样的元素,则返回 none

🔗定义
Array.findFinIdx?.{u} {α : Type u} (p : α Bool) (as : Array α) : Option (Fin as.size)
Array.findFinIdx?.{u} {α : Type u} (p : α Bool) (as : Array α) : Option (Fin as.size)

返回 p 返回 true 的第一个元素的索引,如果没有这样的元素,则返回 none。该索引以 Fin 形式返回,这保证它在范围内。

示例:

🔗定义
Array.findM?.{u_1} {m : Type Type u_1} {α : Type} [Monad m] (p : α m Bool) (as : Array α) : m (Option α)
Array.findM?.{u_1} {m : Type Type u_1} {α : Type} [Monad m] (p : α m Bool) (as : Array α) : m (Option α)

返回一元谓词 p 返回 true 的数组的第一个元素,如果未找到此类元素,则返回 none。按顺序检查数组的元素。

单子 m 仅限于 Type Type,以避免需要使用 ULift Bool 来表示 p 的类型。

例子:

some 1Almost! 6 Almost! 5 #eval #[7, 6, 5, 8, 1, 2, 6].findM? fun i => do if i < 5 then return true if i 6 then IO.println s!"Almost! {i}" return false Almost! 6 Almost! 5some 1
🔗定义
Array.findRevM?.{w} {α : Type} {m : Type Type w} [Monad m] (p : α m Bool) (as : Array α) : m (Option α)
Array.findRevM?.{w} {α : Type} {m : Type Type w} [Monad m] (p : α m Bool) (as : Array α) : m (Option α)

返回数组的最后一个元素,对于该元素,一元谓词 p 返回 true,如果没有找到这样的元素,则返回 none。数组的元素从右到左反向检查。

单子 m 仅限于 Type Type,以避免需要使用 ULift Bool 来表示 p 的类型。

例子:

some 2Almost! 5 Almost! 6 #eval #[7, 5, 8, 1, 2, 6, 5, 8].findRevM? fun i => do if i < 5 then return true if i 6 then IO.println s!"Almost! {i}" return false Almost! 5 Almost! 6some 2
🔗定义
Array.findSome?.{u, v} {α : Type u} {β : Type v} (f : α Option β) (as : Array α) : Option β
Array.findSome?.{u, v} {α : Type u} {β : Type v} (f : α Option β) (as : Array α) : Option β

按顺序返回第一个非 none 结果,它来自把函数 f 应用于数组的各元素。返回值为 none 的条件是:f 对所有元素返回 none

例子:

some 10#eval #[7, 6, 5, 8, 1, 2, 6].findSome? fun i => if i < 5 then some (i * 10) else none some 10
🔗定义
Array.findSome!.{u, v} {α : Type u} {β : Type v} [Inhabited β] (f : α Option β) (xs : Array α) : β
Array.findSome!.{u, v} {α : Type u} {β : Type v} [Inhabited β] (f : α Option β) (xs : Array α) : β

按顺序返回第一个非 none 结果,它来自把函数 f 应用于数组的各元素。如果 f 为所有元素返回 none,则触发错误。

例子:

some 10#eval #[7, 6, 5, 8, 1, 2, 6].findSome? fun i => if i < 5 then some (i * 10) else none some 10
🔗定义
Array.findSomeM?.{u, v, w} {α : Type u} {β : Type v} {m : Type v Type w} [Monad m] (f : α m (Option β)) (as : Array α) : m (Option β)
Array.findSomeM?.{u, v, w} {α : Type u} {β : Type v} {m : Type v Type w} [Monad m] (f : α m (Option β)) (as : Array α) : m (Option β)

按顺序返回第一个非 none 结果,它来自把单子函数 f 应用于数组的各元素。返回值为 none 的条件是:f 对所有元素返回 none

例子:

some 10Almost! 6 Almost! 5 #eval #[7, 6, 5, 8, 1, 2, 6].findSomeM? fun i => do if i < 5 then return some (i * 10) if i 6 then IO.println s!"Almost! {i}" return none Almost! 6 Almost! 5some 10
🔗定义
Array.findSomeRev?.{u, v} {α : Type u} {β : Type v} (f : α Option β) (as : Array α) : Option β
Array.findSomeRev?.{u, v} {α : Type u} {β : Type v} (f : α Option β) (as : Array α) : Option β

返回第一个非 none 结果,它来自按从右到左的相反顺序把 f 应用于数组的各元素。返回值为 none 的条件是:f 对数组的所有元素返回 none

示例:

🔗定义
Array.findSomeRevM?.{u, v, w} {α : Type u} {β : Type v} {m : Type v Type w} [Monad m] (f : α m (Option β)) (as : Array α) : m (Option β)
Array.findSomeRevM?.{u, v, w} {α : Type u} {β : Type v} {m : Type v Type w} [Monad m] (f : α m (Option β)) (as : Array α) : m (Option β)

返回第一个非 none 结果,它来自将单子函数 f 按相反顺序(从右到左)应用于数组的各元素。一旦找到非 none 结果,就不再检查其他元素。返回 none,如果 f 对数组的所有元素都返回 none

示例:

Except.ok (some (-4))#eval #[1, 2, 0, -4, 1].findSomeRevM? (m := Except String) fun x => do if x = 0 then throw "Zero!" else if x < 0 then return (some x) else return none Except.ok (some (-4))Except.error "Zero!"#eval #[1, 2, 0, 4, 1].findSomeRevM? (m := Except String) fun x => do if x = 0 then throw "Zero!" else if x < 0 then return (some x) else return none Except.error "Zero!"
🔗定义
Array.all.{u} {α : Type u} (as : Array α) (p : α Bool) (start : Nat := 0) (stop : Nat := as.size) : Bool
Array.all.{u} {α : Type u} (as : Array α) (p : α Bool) (start : Nat := 0) (stop : Nat := as.size) : Bool

返回值为 true 的条件是:p 对每个元素都返回 true,这些元素来自 as

遇到第一个 false 时短路。

可选参数 startstop 控制要检查的数组区域。仅检查索引从 start(含)到 stop(不含)的元素。默认情况下,检查整个数组。

示例:

  • #[a, b, c].all p = (p a && (p b && p c))

  • #[2, 4, 6].all (· % 2 = 0) = true

  • #[2, 4, 5, 6].all (· % 2 = 0) = false

🔗定义
Array.allM.{u, w} {α : Type u} {m : Type Type w} [Monad m] (p : α m Bool) (as : Array α) (start : Nat := 0) (stop : Nat := as.size) : m Bool
Array.allM.{u, w} {α : Type u} {m : Type Type w} [Monad m] (p : α m Bool) (as : Array α) (start : Nat := 0) (stop : Nat := as.size) : m Bool

返回值为 true 的条件是:单子谓词 p 对每个元素都返回 true,这些元素来自 as

遇到第一个 false 时短路。按从左到右的顺序检查 as 中的元素。

可选参数 startstop 控制要检查的数组区域。仅检查索引从 start(含)到 stop(不含)的元素。默认情况下,检查整个数组。

🔗定义
Array.any.{u} {α : Type u} (as : Array α) (p : α Bool) (start : Nat := 0) (stop : Nat := as.size) : Bool
Array.any.{u} {α : Type u} (as : Array α) (p : α Bool) (start : Nat := 0) (stop : Nat := as.size) : Bool

返回值为 true 的条件是:p 对任一元素返回 true,这些元素来自 as

遇到第一个 true 时短路。

可选参数 startstop 控制要检查的数组区域。仅检查索引从 start(含)到 stop(不含)的元素。默认情况下,检查整个数组。

示例:

  • #[2, 4, 6].any (· % 2 = 0) = true

  • #[2, 4, 6].any (· % 2 = 1) = false

  • #[2, 4, 5, 6].any (· % 2 = 0) = true

  • #[2, 4, 5, 6].any (· % 2 = 1) = true

🔗定义
Array.anyM.{u, w} {α : Type u} {m : Type Type w} [Monad m] (p : α m Bool) (as : Array α) (start : Nat := 0) (stop : Nat := as.size) : m Bool
Array.anyM.{u, w} {α : Type u} {m : Type Type w} [Monad m] (p : α m Bool) (as : Array α) (start : Nat := 0) (stop : Nat := as.size) : m Bool

返回值为 true 的条件是:单子谓词 p 对任一元素返回 true,这些元素来自 as

遇到第一个 true 时短路。按从左到右的顺序检查 as 中的元素。

可选参数 startstop 控制要检查的数组区域。仅检查索引从 start(含)到 stop(不含)的元素。默认情况下,检查整个数组。

🔗定义
Array.allDiff.{u} {α : Type u} [BEq α] (as : Array α) : Bool
Array.allDiff.{u} {α : Type u} [BEq α] (as : Array α) : Bool

返回值为 true 的条件是:as 中没有两个元素按照 == 运算符相等。

示例:

🔗定义
Array.isEqv.{u} {α : Type u} (xs ys : Array α) (p : α α Bool) : Bool
Array.isEqv.{u} {α : Type u} (xs ys : Array α) (p : α α Bool) : Bool

返回值为 true 的条件是:asbs 长度相同且由 eqv 成对关联。

第一对不相关的元件发生短路。

示例:

20.16.4.13. 比较🔗

🔗定义
Array.isPrefixOf.{u} {α : Type u} [BEq α] (as bs : Array α) : Bool
Array.isPrefixOf.{u} {α : Type u} [BEq α] (as bs : Array α) : Bool

返回值为 true 的条件是:asbs 的前缀,否则返回 false

示例:

🔗定义
Array.lex.{u_1} {α : Type u_1} [BEq α] (as bs : Array α) (lt : α α Bool := by exact < ·)) : Bool
Array.lex.{u_1} {α : Type u_1} [BEq α] (as bs : Array α) (lt : α α Bool := by exact < ·)) : Bool

按字典顺序比较数组及其元素上的比较 lt

具体来说,如果 Array.lex as bs lt 为真,则

  • bs 大于 as 并且 as 通过 == 成对等效于 bs 的初始段, 或者

  • 存在索引 i,例如 lt as[i] bs[i],并且对于所有 j < ias[j] == bs[j]

20.16.4.14. 终止辅助🔗

🔗定义
Array.attach.{u_1} {α : Type u_1} (xs : Array α) : Array { x // x xs }
Array.attach.{u_1} {α : Type u_1} (xs : Array α) : Array { x // x xs }

“附加”证明,证明 xs 的元素实际上是 xs 的元素,从而生成具有相同元素但子类型为 { x // x xs } 的新数组。

O(1)

此函数主要用于证明从数组中取出的值小于数组中的对应值,从而允许在良基递归定义中使用 Array.map 等高阶函数。这使良基递归机制能够证明函数终止。

🔗定义
Array.attachWith.{u_1} {α : Type u_1} (xs : Array α) (P : α Prop) (H : (x : α), x xs P x) : Array { x // P x }
Array.attachWith.{u_1} {α : Type u_1} (xs : Array α) (P : α Prop) (H : (x : α), x xs P x) : Array { x // P x }

将各个证明“附加”到满足谓词 P 的值数组,返回相应子类型 { x // P x } 中的元素数组。

O(1)

🔗定义
Array.unattach.{u_1} {α : Type u_1} {p : α Prop} (xs : Array { x // p x }) : Array α
Array.unattach.{u_1} {α : Type u_1} {p : α Prop} (xs : Array { x // p x }) : Array α

通过忘记它们满足谓词,将子类型中的术语数组映射到类型中的相应术语。

这是 Array.attachWith 的逆值,也是 xs.map (·.val) 的同义词。

大多数情况下,用户不需要这样做。它是由诸如 map_subtype 之类的引理作为中间步骤引入的,并且理想情况下随后由 unattach_attach 进行简化。

该函数通常由 Lean 自动插入,作为证明终止性时的中间步骤,很少在代码中显式使用。精化良基递归定义时会引入它。如果在证明状态中遇到此函数,通常应使用策略 simp [Array.unattach, -Array.map_subtype]

🔗定义
Array.pmap.{u_1, u_2} {α : Type u_1} {β : Type u_2} {P : α Prop} (f : (a : α) P a β) (xs : Array α) (H : (a : α), a xs P a) : Array β
Array.pmap.{u_1, u_2} {α : Type u_1} {β : Type u_2} {P : α Prop} (f : (a : α) P a β) (xs : Array α) (H : (a : α), a xs P a) : Array β

将部分定义的函数(定义于 α 中满足谓词 P 的项上)映射到数组 xs : Array α,并给出 xs 的每个元素实际上满足 P 的证明。

Array.pmap,以“部分映射”命名,相当于此类部分函数的 Array.map

20.16.5. 子数组🔗

类型 Subarray αStd.Slice α 的缩写。 这意味着,除了本节中的运算符外,还可以使用泛化字段记号来调用 Std.Slice 命名空间中的函数,例如 Std.Slice.foldl

🔗定义
Subarray.{u} (α : Type u) : Type u
Subarray.{u} (α : Type u) : Type u

某些底层数组的区域。

子数组包含一个数组以及感兴趣区域的起始索引和结束索引。子数组可用于避免复制或分配空间,同时比手动跟踪边界更方便。感兴趣区域由大于或等于 start 且严格小于 stop 的每个索引组成。

🔗定义
Subarray.empty.{u_1} {α : Type u_1} : Subarray α
Subarray.empty.{u_1} {α : Type u_1} : Subarray α

空子数组。

这个空子数组由一个空数组支持。

20.16.5.1. 数组数据🔗

🔗定义
Subarray.array.{u_1} {α : Type u_1} (xs : Subarray α) : Array α
Subarray.array.{u_1} {α : Type u_1} (xs : Subarray α) : Array α

底层数组。

🔗定义
Subarray.start.{u_1} {α : Type u_1} (xs : Subarray α) : Nat
Subarray.start.{u_1} {α : Type u_1} (xs : Subarray α) : Nat

感兴趣区域的起始索引(含)。

🔗定义
Subarray.stop.{u_1} {α : Type u_1} (xs : Subarray α) : Nat
Subarray.stop.{u_1} {α : Type u_1} (xs : Subarray α) : Nat

感兴趣区域的结束索引(不包括)。

🔗定义
Subarray.start_le_stop.{u_1} {α : Type u_1} (xs : Subarray α) : xs.start xs.stop
Subarray.start_le_stop.{u_1} {α : Type u_1} (xs : Subarray α) : xs.start xs.stop

起始索引不晚于结束索引。

结束索引是排他的。如果起始索引和结束索引相等,则子数组为空。

🔗定义
Subarray.stop_le_array_size.{u_1} {α : Type u_1} (xs : Subarray α) : xs.stop xs.array.size
Subarray.stop_le_array_size.{u_1} {α : Type u_1} (xs : Subarray α) : xs.stop xs.array.size

停止索引不晚于数组末尾。

结束索引是排他的。如果它等于数组的大小,则数组的最后一个元素在子数组中。

20.16.5.2. 调整大小🔗

🔗定义
Subarray.drop.{u_1} {α : Type u_1} (arr : Subarray α) (i : Nat) : Subarray α
Subarray.drop.{u_1} {α : Type u_1} (arr : Subarray α) (i : Nat) : Subarray α

删除子数组的第一个 i 元素。如果元素数量为 i 或更少,则生成的子数组为空。

🔗定义
Subarray.take.{u_1} {α : Type u_1} (arr : Subarray α) (i : Nat) : Subarray α
Subarray.take.{u_1} {α : Type u_1} (arr : Subarray α) (i : Nat) : Subarray α

仅保留子数组的前 i 元素。如果元素数量为 i 或更少,则生成的子数组为空。

🔗定义
Subarray.popFront.{u_1} {α : Type u_1} (s : Subarray α) : Subarray α
Subarray.popFront.{u_1} {α : Type u_1} (s : Subarray α) : Subarray α

如果可能的话,通过增加其起始索引来缩小子数组,否则返回原样。

示例:

🔗定义
Subarray.split.{u_1} {α : Type u_1} (s : Subarray α) (i : Fin (Std.Slice.size s).succ) : Subarray α × Subarray α
Subarray.split.{u_1} {α : Type u_1} (s : Subarray α) (i : Fin (Std.Slice.size s).succ) : Subarray α × Subarray α

将子数组分为两部分,第一部分包含第一个 i 元素,第二部分包含其余部分。

20.16.5.3. 查找🔗

🔗定义
Subarray.get.{u_1} {α : Type u_1} (s : Subarray α) (i : Fin (Std.Slice.size s)) : α
Subarray.get.{u_1} {α : Type u_1} (s : Subarray α) (i : Fin (Std.Slice.size s)) : α

从子数组中提取一个元素。

索引是相对于子数组的开头,而不是相对于底层数组。

🔗定义
Subarray.get!.{u_1} {α : Type u_1} [Inhabited α] (s : Subarray α) (i : Nat) : α
Subarray.get!.{u_1} {α : Type u_1} [Inhabited α] (s : Subarray α) (i : Nat) : α

从子数组中提取元素,或者当索引越界时返回默认值。

索引是相对于子数组的开头和结尾,而不是相对于底层数组。默认值是 Inhabited α 实例提供的值。

🔗定义
Subarray.getD.{u_1} {α : Type u_1} (s : Subarray α) (i : Nat) (v₀ : α) : α
Subarray.getD.{u_1} {α : Type u_1} (s : Subarray α) (i : Nat) (v₀ : α) : α

从子数组中提取元素,或者当索引越界时返回默认值 v₀

索引是相对于子数组的开头和结尾,而不是相对于底层数组。

20.16.5.4. 迭代🔗

🔗定义
Subarray.foldr.{u, v} {α : Type u} {β : Type v} (f : α β β) (init : β) (as : Subarray α) : β
Subarray.foldr.{u, v} {α : Type u} {β : Type v} (f : α β β) (init : β) (as : Subarray α) : β

在子数组中的元素上从右向左折叠操作。

β 类型的累加器的构造方法是从 init 开始,依次将子数组的每个元素与当前累加器值相结合,从末尾移动到开头。

示例:

🔗定义
Subarray.foldrM.{u, v, w} {α : Type u} {β : Type v} {m : Type v Type w} [Monad m] (f : α β m β) (init : β) (as : Subarray α) : m β
Subarray.foldrM.{u, v, w} {α : Type u} {β : Type v} {m : Type v Type w} [Monad m] (f : α β m β) (init : β) (as : Subarray α) : m β

在子数组中的元素上从右向左折叠一元运算。

β 类型的累加器是通过以下方式构造的:从 init 开始,依次将子数组的每个元素与当前累加器值进行一元组合,从末尾移动到开头。所讨论的单子可能允许提前终止或重复。

示例:

some "(4)blue (5)green (3)red "#eval #["red", "green", "blue"].toSubarray.foldrM (init := "") fun x acc => do let l Option.guard (· 0) x.length return s!"{acc}({l}){x} " some "(4)blue (5)green (3)red "
#eval #["red", "green", "blue"].toSubarray.foldrM (init := 0) fun x acc => do
  let l ← Option.guard (· ≠ 5) x.length
  return s!"{acc}({l}){x} "
none
🔗定义
Subarray.forM.{u, v, w} {α : Type u} {m : Type v Type w} [Monad m] (f : α m PUnit) (as : Subarray α) : m PUnit
Subarray.forM.{u, v, w} {α : Type u} {m : Type v Type w} [Monad m] (f : α m PUnit) (as : Subarray α) : m PUnit

对子数组的每个元素运行一元操作。

从最低索引开始处理元素并向上移动。

🔗定义
Subarray.forRevM.{u, v, w} {α : Type u} {m : Type v Type w} [Monad m] (f : α m PUnit) (as : Subarray α) : m PUnit
Subarray.forRevM.{u, v, w} {α : Type u} {m : Type v Type w} [Monad m] (f : α m PUnit) (as : Subarray α) : m PUnit

以相反的顺序对子数组的每个元素运行一元操作。

从最高索引开始处理元素并向下移动。

🔗定义
Subarray.forIn.{v, w, u} {α : Type u} {β : Type v} {m : Type v Type w} [Monad m] (s : Subarray α) (b : β) (f : α β m (ForInStep β)) : m β
Subarray.forIn.{v, w, u} {α : Type u} {β : Type v} {m : Type v Type w} [Monad m] (s : Subarray α) (b : β) (f : α β m (ForInStep β)) : m β

ForIn.forIn 针对 Subarray 的实现,使其可用于 for 循环的 do 记法。

20.16.5.5. 元素谓词🔗

🔗定义
Subarray.findRev? {α : Type} (as : Subarray α) (p : α Bool) : Option α
Subarray.findRev? {α : Type} (as : Subarray α) (p : α Bool) : Option α

使用布尔谓词以相反顺序测试子数组中的每个元素,在满足谓词的第一个元素处停止。返回满足谓词的元素,如果没有元素满足谓词,则返回 none

示例:

🔗定义
Subarray.findRevM?.{w} {α : Type} {m : Type Type w} [Monad m] (as : Subarray α) (p : α m Bool) : m (Option α)
Subarray.findRevM?.{w} {α : Type} {m : Type Type w} [Monad m] (as : Subarray α) (p : α m Bool) : m (Option α)

以相反的顺序将一元布尔谓词应用于子数组中的每个元素,在满足谓词的第一个元素处停止。返回满足谓词的元素,如果没有元素满足它,则返回 none

例子:

some "green"blue green #eval #["red", "green", "blue"].toSubarray.findRevM? fun x => do IO.println x return (x.length = 5) blue greensome 5
🔗定义
Subarray.findSomeRevM?.{u, v, w} {α : Type u} {β : Type v} {m : Type v Type w} [Monad m] (as : Subarray α) (f : α m (Option β)) : m (Option β)
Subarray.findSomeRevM?.{u, v, w} {α : Type u} {β : Type v} {m : Type v Type w} [Monad m] (as : Subarray α) (f : α m (Option β)) : m (Option β)

以相反的顺序将一元函数应用于子数组中的每个元素,并在函数成功的第一个元素处停止,返回 none 以外的值。返回后续值,如果不成功则返回 none

例子:

some 5blue green #eval #["red", "green", "blue"].toSubarray.findSomeRevM? fun x => do IO.println x return Option.guard (· = 5) x.length blue greensome 5
🔗定义
Subarray.all.{u} {α : Type u} (p : α Bool) (as : Subarray α) : Bool
Subarray.all.{u} {α : Type u} (p : α Bool) (as : Subarray α) : Bool

检查子数组中的所有元素是否满足布尔谓词。

从最低索引开始并向上移动元素进行测试。一旦找到不满足谓词的元素,搜索就会终止。

🔗定义
Subarray.allM.{u, w} {α : Type u} {m : Type Type w} [Monad m] (p : α m Bool) (as : Subarray α) : m Bool
Subarray.allM.{u, w} {α : Type u} {m : Type Type w} [Monad m] (p : α m Bool) (as : Subarray α) : m Bool

检查子数组中的所有元素是否满足一元布尔谓词。

从最低索引开始并向上移动元素进行测试。一旦找到不满足谓词的元素,搜索就会终止。

例子:

falsegreen blue #eval #["red", "green", "blue", "orange"].toSubarray.popFront.allM fun x => do IO.println x pure (x.length == 5) green bluefalse
🔗定义
Subarray.any.{u} {α : Type u} (p : α Bool) (as : Subarray α) : Bool
Subarray.any.{u} {α : Type u} (p : α Bool) (as : Subarray α) : Bool

检查子数组中的任何元素是否满足布尔谓词。

从最低索引开始并向上移动元素进行测试。一旦找到满足谓词的元素,搜索就会终止。

🔗定义
Subarray.anyM.{u, w} {α : Type u} {m : Type Type w} [Monad m] (p : α m Bool) (as : Subarray α) : m Bool
Subarray.anyM.{u, w} {α : Type u} {m : Type Type w} [Monad m] (p : α m Bool) (as : Subarray α) : m Bool

检查子数组中的任何元素是否满足一元布尔谓词。

从最低索引开始并向上移动元素进行测试。一旦找到满足谓词的元素,搜索就会终止。

例子:

truegreen blue #eval #["red", "green", "blue", "orange"].toSubarray.popFront.anyM fun x => do IO.println x pure (x == "blue") green bluetrue

20.16.6. FFI🔗

FFI type
typedef struct {
    lean_object   m_header;
    size_t        m_size;
    size_t        m_capacity;
    lean_object * m_data[];
} lean_array_object;

数组在 C 中的表示。更多细节请参阅运行时 Array 的说明。

FFI function
bool lean_is_array(lean_object * o)

返回 true 表示 o 是数组;否则返回 false

FFI function
lean_array_object * lean_to_array(lean_object * o)

执行运行时检查,确认 o 确实是数组。如果 o 不是数组,断言将失败。