Lean 语言参考

20.3. 有限自然数🔗

对于任何 自然数 nFin n 是包含严格小于 n 的所有自然数的类型。 换句话说,Fin n 恰好具有 n 元素。 它可用于表示列表或数组中的有效索引,也可用作规范的 n 元素类型。

🔗structure
Fin (n : Nat) : Type
Fin (n : Nat) : Type

Natural numbers less than some upper bound.

In particular, a Fin n is a natural number i with the constraint that i < n. It is the canonical type with n elements.

Constructor

Fin.mk

Creates a Fin n from i : Nat and a proof that i < n.

Fields

val : Nat

The number that is strictly less than n.

Fin.val is a coercion, so any Fin n can be used in a position where a Nat is expected.

isLt : self < n

The number val is strictly less than the bound n.

FinUInt8UInt16UInt32UInt64USize 密切相关,它们也表示有限非负积分类型。 但是,这些类型由位向量而不是自然数支持,并且它们具有固定的边界。 Fin 相对更灵活,但对于底层推理来说不太方便。 特别是,使用位向量而不是证明数字小于 2 的某个幂可以避免需要注意避免评估具体界限。

20.3.1. 运行时特性🔗

因为 Fin n 是一个只有单个字段不是证明的结构,所以它是一个 平凡的包装器。 这意味着它在编译代码中的表示方式与底层自然数相同。

20.3.2. 强制和文字🔗

有一个从 Fin nNat强制,它丢弃数字小于界限的证明。 特别地,这个强制正是投影Fin.val。 这样做的结果之一是 Fin.val 的使用显示为强制,而不是证明状态中的显式投影。

Coercing from Fin to Nat

Fin n 可以用在需要 Nat 的地方:

1#eval let one : Fin 3 := 1, n:Nat1 < 3 All goals completed! 🐙; (one : Nat)
1

Fin.val 的使用在证明状态中显示为强制:

n:Nati:Fin ni < n

自然数文字可用于 Fin 类型,通过 OfNat 实例照常实现。 Fin nOfNat 实例要求上限 n 不为零,但不检查文字是否小于 n。 如果文字大于类型可以表示的值,则使用它除以 n 时的余数。

Numeric Literals for Fin

如果 n > 0,则自然数文字可用于 Fin n

example : Fin 5 := 3 example : Fin 20 := 19

当文字大于或等于n时,使用除以n时的余数:

2#eval (5 : Fin 3)
2
[0, 1, 2, 0, 1, 2, 0]#eval ([0, 1, 2, 3, 4, 5, 6] : List (Fin 3))
[0, 1, 2, 0, 1, 2, 0]

如果 Lean 无法合成 NeZero n 的实例,则不存在 OfNat (Fin n) 实例:

example : Fin 0 := failed to synthesize instance of type class OfNat (Fin 0) 0 numerals are polymorphic in Lean, but the numeral `0` cannot be used in a context where the expected type is Fin 0 due to the absence of the instance above Hint: Type class instance resolution failures can be inspected with the `set_option trace.Meta.synthInstance true` command.0
failed to synthesize instance of type class
  OfNat (Fin 0) 0
numerals are polymorphic in Lean, but the numeral `0` cannot be used in a context where the expected type is
  Fin 0
due to the absence of the instance above

Hint: Type class instance resolution failures can be inspected with the `set_option trace.Meta.synthInstance true` command.
example (k : Nat) : Fin k := failed to synthesize instance of type class OfNat (Fin k) 0 numerals are polymorphic in Lean, but the numeral `0` cannot be used in a context where the expected type is Fin k due to the absence of the instance above Hint: Type class instance resolution failures can be inspected with the `set_option trace.Meta.synthInstance true` command.0
failed to synthesize instance of type class
  OfNat (Fin k) 0
numerals are polymorphic in Lean, but the numeral `0` cannot be used in a context where the expected type is
  Fin k
due to the absence of the instance above

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

20.3.3. API 参考🔗

20.3.3.1. 建造🔗

🔗def
Fin.last (n : Nat) : Fin (n + 1)
Fin.last (n : Nat) : Fin (n + 1)

The greatest value of Fin (n+1), namely n.

Examples:

🔗def
Fin.succ {n : Nat} : Fin n Fin (n + 1)
Fin.succ {n : Nat} : Fin n Fin (n + 1)

The successor, with an increased bound.

This differs from adding 1, which instead wraps around.

Examples:

🔗def
Fin.pred {n : Nat} (i : Fin (n + 1)) (h : i 0) : Fin n
Fin.pred {n : Nat} (i : Fin (n + 1)) (h : i 0) : Fin n

The predecessor of a non-zero element of Fin (n+1), with the bound decreased.

Examples:

20.3.3.2. 算术🔗

通常,Fin 上的算术运算应使用 Lean 的重载算术表示法进行访问,特别是通过实例 Add (Fin n)Sub (Fin n)Mul (Fin n)Div (Fin n)Mod (Fin n)。 诸如 Fin.natAdd 之类的异构运算符没有相应的异构实例(例如 HAdd),以避免混淆类型推断行为。

🔗def
Fin.add {n : Nat} : Fin n Fin n Fin n
Fin.add {n : Nat} : Fin n Fin n Fin n

Addition modulo n, usually invoked via the + operator.

Examples:

🔗def
Fin.natAdd {m : Nat} (n : Nat) (i : Fin m) : Fin (n + m)
Fin.natAdd {m : Nat} (n : Nat) (i : Fin m) : Fin (n + m)

Adds a natural number to a Fin, increasing the bound.

This is a generalization of Fin.succ.

Fin.addNat is a version of this function that takes its Nat parameter second.

Examples:

🔗def
Fin.addNat {n : Nat} (i : Fin n) (m : Nat) : Fin (n + m)
Fin.addNat {n : Nat} (i : Fin n) (m : Nat) : Fin (n + m)

Adds a natural number to a Fin, increasing the bound.

This is a generalization of Fin.succ.

Fin.natAdd is a version of this function that takes its Nat parameter first.

Examples:

🔗def
Fin.mul {n : Nat} : Fin n Fin n Fin n
Fin.mul {n : Nat} : Fin n Fin n Fin n

Multiplication modulo n, usually invoked via the * operator.

Examples:

🔗def
Fin.sub {n : Nat} : Fin n Fin n Fin n
Fin.sub {n : Nat} : Fin n Fin n Fin n

Subtraction modulo n, usually invoked via the - operator.

Examples:

🔗def
Fin.subNat {n : Nat} (m : Nat) (i : Fin (n + m)) (h : m i) : Fin n
Fin.subNat {n : Nat} (m : Nat) (i : Fin (n + m)) (h : m i) : Fin n

Subtraction of a natural number from a Fin, with the bound narrowed.

This is a generalization of Fin.pred. It is guaranteed to not underflow or wrap around.

Examples:

🔗def
Fin.div {n : Nat} : Fin n Fin n Fin n
Fin.div {n : Nat} : Fin n Fin n Fin n

Division of bounded numbers, usually invoked via the / operator.

The resulting value is that computed by the / operator on Nat. In particular, the result of division by 0 is 0.

Examples:

🔗def
Fin.mod {n : Nat} : Fin n Fin n Fin n
Fin.mod {n : Nat} : Fin n Fin n Fin n

Modulus of bounded numbers, usually invoked via the % operator.

The resulting value is that computed by the % operator on Nat.

🔗def
Fin.modn {n : Nat} : Fin n Nat Fin n
Fin.modn {n : Nat} : Fin n Nat Fin n

Modulus of bounded numbers with respect to a Nat.

The resulting value is that computed by the % operator on Nat.

🔗def
Fin.log2 {m : Nat} (n : Fin m) : Fin m
Fin.log2 {m : Nat} (n : Fin m) : Fin m

Logarithm base 2 for bounded numbers.

The resulting value is the same as that computed by Nat.log2. In particular, the result for 0 is 0.

Examples:

20.3.3.3. 按位运算🔗

🔗def
Fin.shiftLeft {n : Nat} : Fin n Fin n Fin n
Fin.shiftLeft {n : Nat} : Fin n Fin n Fin n

Bitwise left shift of bounded numbers, with wraparound on overflow.

Examples:

  • (1 : Fin 10) <<< (1 : Fin 10) = (2 : Fin 10)

  • (1 : Fin 10) <<< (3 : Fin 10) = (8 : Fin 10)

  • (1 : Fin 10) <<< (4 : Fin 10) = (6 : Fin 10)

🔗def
Fin.shiftRight {n : Nat} : Fin n Fin n Fin n
Fin.shiftRight {n : Nat} : Fin n Fin n Fin n

Bitwise right shift of bounded numbers.

This operator corresponds to logical rather than arithmetic bit shifting. The new bits are always 0.

Examples:

  • (15 : Fin 16) >>> (1 : Fin 16) = (7 : Fin 16)

  • (15 : Fin 16) >>> (2 : Fin 16) = (3 : Fin 16)

  • (15 : Fin 17) >>> (2 : Fin 17) = (3 : Fin 17)

🔗def
Fin.land {n : Nat} : Fin n Fin n Fin n
Fin.land {n : Nat} : Fin n Fin n Fin n

Bitwise and.

🔗def
Fin.lor {n : Nat} : Fin n Fin n Fin n
Fin.lor {n : Nat} : Fin n Fin n Fin n

Bitwise or.

🔗def
Fin.xor {n : Nat} : Fin n Fin n Fin n
Fin.xor {n : Nat} : Fin n Fin n Fin n

Bitwise xor (“exclusive or”).

20.3.3.4. 转换🔗

🔗def
Fin.toNat {n : Nat} (i : Fin n) : Nat
Fin.toNat {n : Nat} (i : Fin n) : Nat

Extracts the underlying Nat value.

This function is a synonym for Fin.val, which is the simp normal form. Fin.val is also a coercion, so values of type Fin n are automatically converted to Nats as needed.

🔗def
Fin.ofNat (n : Nat) [NeZero n] (a : Nat) : Fin n
Fin.ofNat (n : Nat) [NeZero n] (a : Nat) : Fin n

Returns a modulo n as a Fin n.

The assumption NeZero n ensures that Fin n is nonempty.

🔗def
Fin.cast {n m : Nat} (eq : n = m) (i : Fin n) : Fin m
Fin.cast {n m : Nat} (eq : n = m) (i : Fin n) : Fin m

Uses a proof that two bounds are equal to allow a value bounded by one to be used with the other.

In other words, when eq : n = m, Fin.cast eq i converts i : Fin n into a Fin m.

🔗def
Fin.castLT {n m : Nat} (i : Fin m) (h : i < n) : Fin n
Fin.castLT {n m : Nat} (i : Fin m) (h : i < n) : Fin n

Replaces the bound with another that is suitable for the value.

The proof embedded in i can be used to cast to a larger bound even if the concrete value is not known.

Examples:

example : Fin 12 := (7 : Fin 10).castLT (7 < 12 All goals completed! 🐙 : 7 < 12) example (i : Fin 10) : Fin 12 := i.castLT <| i:Fin 10i < 12 val✝:NatisLt✝:val✝ < 10val✝, isLt✝ < 12; val✝:NatisLt✝:val✝ < 10val✝ < 12; All goals completed! 🐙
🔗def
Fin.castLE {n m : Nat} (h : n m) (i : Fin n) : Fin m
Fin.castLE {n m : Nat} (h : n m) (i : Fin n) : Fin m

Coarsens a bound to one at least as large.

See also Fin.castAdd for a version that represents the larger bound with addition rather than an explicit inequality proof.

🔗def
Fin.castAdd {n : Nat} (m : Nat) : Fin n Fin (n + m)
Fin.castAdd {n : Nat} (m : Nat) : Fin n Fin (n + m)

Coarsens a bound to one at least as large.

See also Fin.natAdd and Fin.addNat for addition functions that increase the bound, and Fin.castLE for a version that uses an explicit inequality proof.

🔗def
Fin.castSucc {n : Nat} : Fin n Fin (n + 1)
Fin.castSucc {n : Nat} : Fin n Fin (n + 1)

Coarsens a bound by one.

🔗def
Fin.rev {n : Nat} (i : Fin n) : Fin n
Fin.rev {n : Nat} (i : Fin n) : Fin n

Replaces a value with its difference from the largest value in the type.

Considering the values of Fin n as a sequence 0, 1, …, n-2, n-1, Fin.rev finds the corresponding element of the reversed sequence. In other words, it maps 0 to n-1, 1 to n-2, ..., and n-1 to 0.

Examples:

🔗def
Fin.elim0.{u} {α : Sort u} : Fin 0 α
Fin.elim0.{u} {α : Sort u} : Fin 0 α

The type Fin 0 is uninhabited, so it can be used to derive any result whatsoever.

This is similar to Empty.elim. It can be thought of as a compiler-checked assertion that a code path is unreachable, or a logical contradiction from which False and thus anything else could be derived.

20.3.3.5. 迭代🔗

🔗def
Fin.foldr.{u_1} {α : Sort u_1} (n : Nat) (f : Fin n α α) (init : α) : α
Fin.foldr.{u_1} {α : Sort u_1} (n : Nat) (f : Fin n α α) (init : α) : α

Combine all the values that can be represented by Fin n with an initial value, starting at n - 1 and nesting to the right.

Example:

🔗def
Fin.foldrM.{u_1, u_2} {m : Type u_1 Type u_2} {α : Type u_1} [Monad m] (n : Nat) (f : Fin n α m α) (init : α) : m α
Fin.foldrM.{u_1, u_2} {m : Type u_1 Type u_2} {α : Type u_1} [Monad m] (n : Nat) (f : Fin n α m α) (init : α) : m α

Folds a monadic function over Fin n from right to left, starting with n-1.

It is the sequence of steps:

Fin.foldrM n f xₙ = do
  let xₙ₋₁ ← f (n-1) xₙ
  let xₙ₋₂ ← f (n-2) xₙ₋₁
  ...
  let x₀ ← f 0 x₁
  pure x₀
🔗def
Fin.foldl.{u_1} {α : Sort u_1} (n : Nat) (f : α Fin n α) (init : α) : α
Fin.foldl.{u_1} {α : Sort u_1} (n : Nat) (f : α Fin n α) (init : α) : α

Combine all the values that can be represented by Fin n with an initial value, starting at 0 and nesting to the left.

Example:

🔗def
Fin.foldlM.{u_1, u_2} {m : Type u_1 Type u_2} {α : Type u_1} [Monad m] (n : Nat) (f : α Fin n m α) (init : α) : m α
Fin.foldlM.{u_1, u_2} {m : Type u_1 Type u_2} {α : Type u_1} [Monad m] (n : Nat) (f : α Fin n m α) (init : α) : m α

Folds a monadic function over all the values in Fin n from left to right, starting with 0.

It is the sequence of steps:

Fin.foldlM n f x₀ = do
  let x₁ ← f x₀ 0
  let x₂ ← f x₁ 1
  ...
  let xₙ ← f xₙ₋₁ (n-1)
  pure xₙ
🔗def
Fin.hIterate.{u_1} (P : Nat Sort u_1) {n : Nat} (init : P 0) (f : (i : Fin n) P i P (i + 1)) : P n
Fin.hIterate.{u_1} (P : Nat Sort u_1) {n : Nat} (init : P 0) (f : (i : Fin n) P i P (i + 1)) : P n

Applies an index-dependent function to all the values less than the given bound n, starting at 0 with an accumulator.

Concretely, Fin.hIterate P init f is equal to

  init |> f 0 |> f 1 |> ... |> f (n-1)

Theorems about Fin.hIterate can be proven using the general theorem Fin.hIterate_elim or other more specialized theorems.

Fin.hIterateFrom is a variant that takes a custom starting value instead of 0.

🔗def
Fin.hIterateFrom.{u_1} (P : Nat Sort u_1) {n : Nat} (f : (i : Fin n) P i P (i + 1)) (i : Nat) (ubnd : i n) (a : P i) : P n
Fin.hIterateFrom.{u_1} (P : Nat Sort u_1) {n : Nat} (f : (i : Fin n) P i P (i + 1)) (i : Nat) (ubnd : i n) (a : P i) : P n

Applies an index-dependent function f to all of the values in [i:n], starting at i with an initial accumulator a.

Concretely, Fin.hIterateFrom P f i a is equal to

  a |> f i |> f (i + 1) |> ... |> f (n - 1)

Theorems about Fin.hIterateFrom can be proven using the general theorem Fin.hIterateFrom_elim or other more specialized theorems.

Fin.hIterate is a variant that always starts at 0.

20.3.3.6. 推理🔗

🔗def
Fin.induction.{u_1} {n : Nat} {motive : Fin (n + 1) Sort u_1} (zero : motive 0) (succ : (i : Fin n) motive i.castSucc motive i.succ) (i : Fin (n + 1)) : motive i
Fin.induction.{u_1} {n : Nat} {motive : Fin (n + 1) Sort u_1} (zero : motive 0) (succ : (i : Fin n) motive i.castSucc motive i.succ) (i : Fin (n + 1)) : motive i

Proves a statement by induction on the underlying Nat value in a Fin (n + 1).

For the induction:

  • zero is the base case, demonstrating motive 0.

  • succ is the inductive step, assuming the motive for i : Fin n (lifted to Fin (n + 1) with Fin.castSucc) and demonstrating it for i.succ.

Fin.inductionOn is a version of this induction principle that takes the Fin as its first parameter, Fin.cases is the corresponding case analysis operator, and Fin.reverseInduction is a version that starts at the greatest value instead of 0.

🔗def
Fin.inductionOn.{u_1} {n : Nat} (i : Fin (n + 1)) {motive : Fin (n + 1) Sort u_1} (zero : motive 0) (succ : (i : Fin n) motive i.castSucc motive i.succ) : motive i
Fin.inductionOn.{u_1} {n : Nat} (i : Fin (n + 1)) {motive : Fin (n + 1) Sort u_1} (zero : motive 0) (succ : (i : Fin n) motive i.castSucc motive i.succ) : motive i

Proves a statement by induction on the underlying Nat value in a Fin (n + 1).

For the induction:

  • zero is the base case, demonstrating motive 0.

  • succ is the inductive step, assuming the motive for i : Fin n (lifted to Fin (n + 1) with Fin.castSucc) and demonstrating it for i.succ.

Fin.induction is a version of this induction principle that takes the Fin as its last parameter.

🔗def
Fin.reverseInduction.{u_1} {n : Nat} {motive : Fin (n + 1) Sort u_1} (last : motive (Fin.last n)) (cast : (i : Fin n) motive i.succ motive i.castSucc) (i : Fin (n + 1)) : motive i
Fin.reverseInduction.{u_1} {n : Nat} {motive : Fin (n + 1) Sort u_1} (last : motive (Fin.last n)) (cast : (i : Fin n) motive i.succ motive i.castSucc) (i : Fin (n + 1)) : motive i

Proves a statement by reverse induction on the underlying Nat value in a Fin (n + 1).

For the induction:

  • last is the base case, demonstrating motive (Fin.last n).

  • cast is the inductive step, assuming the motive for (j : Fin n).succ and demonstrating it for the predecessor j.castSucc.

Fin.induction is the non-reverse induction principle.

🔗def
Fin.cases.{u_1} {n : Nat} {motive : Fin (n + 1) Sort u_1} (zero : motive 0) (succ : (i : Fin n) motive i.succ) (i : Fin (n + 1)) : motive i
Fin.cases.{u_1} {n : Nat} {motive : Fin (n + 1) Sort u_1} (zero : motive 0) (succ : (i : Fin n) motive i.succ) (i : Fin (n + 1)) : motive i

Proves a statement by cases on the underlying Nat value in a Fin (n + 1).

The two cases are:

  • zero, used when the value is of the form (0 : Fin (n + 1))

  • succ, used when the value is of the form (j : Fin n).succ

The corresponding induction principle is Fin.induction.

🔗def
Fin.lastCases.{u_1} {n : Nat} {motive : Fin (n + 1) Sort u_1} (last : motive (Fin.last n)) (cast : (i : Fin n) motive i.castSucc) (i : Fin (n + 1)) : motive i
Fin.lastCases.{u_1} {n : Nat} {motive : Fin (n + 1) Sort u_1} (last : motive (Fin.last n)) (cast : (i : Fin n) motive i.castSucc) (i : Fin (n + 1)) : motive i

Proves a statement by cases on the underlying Nat value in a Fin (n + 1), checking whether the value is the greatest representable or a predecessor of some other.

The two cases are:

  • last, used when the value is Fin.last n

  • cast, used when the value is of the form (j : Fin n).succ

The corresponding induction principle is Fin.reverseInduction.

🔗def
Fin.addCases.{u} {m n : Nat} {motive : Fin (m + n) Sort u} (left : (i : Fin m) motive (Fin.castAdd n i)) (right : (i : Fin n) motive (Fin.natAdd m i)) (i : Fin (m + n)) : motive i
Fin.addCases.{u} {m n : Nat} {motive : Fin (m + n) Sort u} (left : (i : Fin m) motive (Fin.castAdd n i)) (right : (i : Fin n) motive (Fin.natAdd m i)) (i : Fin (m + n)) : motive i

A case analysis operator for i : Fin (m + n) that separately handles the cases where i < m and where m i < m + n.

The first case, where i < m, is handled by left. In this case, i can be represented as Fin.castAdd n (j : Fin m).

The second case, where m i < m + n, is handled by right. In this case, i can be represented as Fin.natAdd m (j : Fin n).

🔗def
Fin.succRec.{u_1} {motive : (n : Nat) Fin n Sort u_1} (zero : (n : Nat) motive n.succ 0) (succ : (n : Nat) (i : Fin n) motive n i motive n.succ i.succ) {n : Nat} (i : Fin n) : motive n i
Fin.succRec.{u_1} {motive : (n : Nat) Fin n Sort u_1} (zero : (n : Nat) motive n.succ 0) (succ : (n : Nat) (i : Fin n) motive n i motive n.succ i.succ) {n : Nat} (i : Fin n) : motive n i

An induction principle for Fin that considers a given i : Fin n as given by a sequence of i applications of Fin.succ.

The cases in the induction are:

  • zero demonstrates the motive for (0 : Fin (n + 1)) for all bounds n

  • succ demonstrates the motive for Fin.succ applied to an arbitrary Fin for an arbitrary bound n

Unlike Fin.induction, the motive quantifies over the bound, and the bound varies at each inductive step. Fin.succRecOn is a version of this induction principle that takes the Fin argument first.

🔗def
Fin.succRecOn.{u_1} {n : Nat} (i : Fin n) {motive : (n : Nat) Fin n Sort u_1} (zero : (n : Nat) motive (n + 1) 0) (succ : (n : Nat) (i : Fin n) motive n i motive n.succ i.succ) : motive n i
Fin.succRecOn.{u_1} {n : Nat} (i : Fin n) {motive : (n : Nat) Fin n Sort u_1} (zero : (n : Nat) motive (n + 1) 0) (succ : (n : Nat) (i : Fin n) motive n i motive n.succ i.succ) : motive n i

An induction principle for Fin that considers a given i : Fin n as given by a sequence of i applications of Fin.succ.

The cases in the induction are:

  • zero demonstrates the motive for (0 : Fin (n + 1)) for all bounds n

  • succ demonstrates the motive for Fin.succ applied to an arbitrary Fin for an arbitrary bound n

Unlike Fin.induction, the motive quantifies over the bound, and the bound varies at each inductive step. Fin.succRec is a version of this induction principle that takes the Fin argument last.