Lean 4.7.0

Lean 4.7.0 has been released! While this release includes the usual collection of quality-of-life improvements and bug fixes, the most noticable change is that a large part of Std, the external standard library, is included with Lean. Not only does this help with discoverability, it also enabled us to integrate these features more tightly into the rest of the language. In the next few releases, we'll continue to upstream data structures, tactics, proofs, and language features in order to make the out-of-box experience of using Lean as pleasant as possible.

As usual, this announcement post describes selected highlights of the release. For a more complete list of changes and improvements, please refer to the release notes.

Omega

The omega tactic is a decision procedure for a large class of equalities and inequalities of natural numbers and integers that are generated from constants, variables, addition, subtraction, and multiplication by constants. Subexpressions that don't fit this grammar are treated as if they were variables, so omega can also solve goals like fString → Nat xString - 1 < fString → Nat xString + 5 (where fString → Nat xString is treated as if it were a variable).

My colleague Kim Morrison has been working on omega for a few months, and it's been available in Std. There was a prior implementation for Lean 3 by Seul Baek, but the two tactics don't share any code. Because omega is now available out of the box, we've been able to use it in many more contexts, automatically discharging many more proof obligations. The improvement is particularly noticable when working with compile-time bounds checking for array accesses and with recursive functions over numbers.

Array Bounds Checking

In Lean, array lookups are statically bounds-checked by default—writing xsArray α[3] causes Lean to try to prove that 3 < xsArray α.sizeArray.size.{u} {α : Type u} (a : Array α) : NatGet the size of an array. This is a cached value, so it is O(1) to access. . The default tactic used for these goals in Lean 4.6 and earlier would work if precisely this fact were available in the local context, but not if e.g. xsArray α.sizeArray.size.{u} {α : Type u} (a : Array α) : NatGet the size of an array. This is a cached value, so it is O(1) to access. > 18 were available. In Lean 4.7, omega is used for these situations, making static bounds checking much more ergonomic.

Termination Proofs

Similarly, Lean 4.7 uses omega in the process of automatically searching for termination proofs for recursive functions. This means that fewer manually-provided proofs are necessary. For example, given this definition of binary numbers:

inductiveIn Lean, every concrete type other than the universes and every type constructor other than dependent arrows is an instance of a general family of type constructions known as inductive types. It is remarkable that it is possible to construct a substantial edifice of mathematics based on nothing more than the type universes, dependent arrow types, and inductive types; everything else follows from those. Intuitively, an inductive type is built up from a specified list of constructor. For example, `List α` is the list of elements of type `α`, and is defined as follows: ``` inductive List (α : Type u) where | nil | cons (head : α) (tail : List α) ``` A list of elements of type `α` is either the empty list, `nil`, or an element `head : α` followed by a list `tail : List α`. For more information about [inductive types](https://lean-lang.org/theorem_proving_in_lean4/inductive_types.html). Bin_root_.Bin : Type : Type where | zeroBin.zero : Bin | twiceBin.twice (a✝ : Bin) : Bin : Bin_root_.Bin : Type Bin_root_.Bin : Type | succTwiceBin.succTwice (a✝ : Bin) : Bin : Bin_root_.Bin : Type Bin_root_.Bin : Type

a function to convert Nat to Bin is most naturally written with explicit use of division by two:

def Bin.fromNatBin.fromNat (n : Nat) : Bin (nNat : NatNat : TypeThe type of natural numbers, starting at zero. It is defined as an inductive type freely generated by "zero is a natural number" and "the successor of a natural number is a natural number". You can prove a theorem `P n` about `n : Nat` by `induction n`, which will expect a proof of the theorem for `P 0`, and a proof of `P (succ i)` assuming a proof of `P i`. The same method also works to define functions by recursion on natural numbers: induction and recursion are two expressions of the same operation from Lean's point of view. ``` open Nat example (n : Nat) : n < succ n := by induction n with | zero => show 0 < 1 decide | succ i ih => -- ih : i < succ i show succ i < succ (succ i) exact Nat.succ_lt_succ ih ``` This type is special-cased by both the kernel and the compiler: * The type of expressions contains "`Nat` literals" as a primitive constructor, and the kernel knows how to reduce zero/succ expressions to nat literals. * If implemented naively, this type would represent a numeral `n` in unary as a linked list with `n` links, which is horribly inefficient. Instead, the runtime itself has a special representation for `Nat` which stores numbers up to 2^63 directly and larger numbers use an arbitrary precision "bignum" library (usually [GMP](https://gmplib.org/)). ) : BinBin : Type := if`if c then t else e` is notation for `ite c t e`, "if-then-else", which decides to return `t` or `e` depending on whether `c` is true or false. The explicit argument `c : Prop` does not have any actual computational content, but there is an additional `[Decidable c]` argument synthesized by typeclass inference which actually determines how to evaluate `c` to true or false. Write `if h : c then t else e` instead for a "dependent if-then-else" `dite`, which allows `t`/`e` to use the fact that `c` is true/false. nNat = 0 then`if c then t else e` is notation for `ite c t e`, "if-then-else", which decides to return `t` or `e` depending on whether `c` is true or false. The explicit argument `c : Prop` does not have any actual computational content, but there is an additional `[Decidable c]` argument synthesized by typeclass inference which actually determines how to evaluate `c` to true or false. Write `if h : c then t else e` instead for a "dependent if-then-else" `dite`, which allows `t`/`e` to use the fact that `c` is true/false. .zeroBin.zero : Bin else`if c then t else e` is notation for `ite c t e`, "if-then-else", which decides to return `t` or `e` depending on whether `c` is true or false. The explicit argument `c : Prop` does not have any actual computational content, but there is an additional `[Decidable c]` argument synthesized by typeclass inference which actually determines how to evaluate `c` to true or false. Write `if h : c then t else e` instead for a "dependent if-then-else" `dite`, which allows `t`/`e` to use the fact that `c` is true/false. if`if c then t else e` is notation for `ite c t e`, "if-then-else", which decides to return `t` or `e` depending on whether `c` is true or false. The explicit argument `c : Prop` does not have any actual computational content, but there is an additional `[Decidable c]` argument synthesized by typeclass inference which actually determines how to evaluate `c` to true or false. Write `if h : c then t else e` instead for a "dependent if-then-else" `dite`, which allows `t`/`e` to use the fact that `c` is true/false. nNat % 2 = 0 then`if c then t else e` is notation for `ite c t e`, "if-then-else", which decides to return `t` or `e` depending on whether `c` is true or false. The explicit argument `c : Prop` does not have any actual computational content, but there is an additional `[Decidable c]` argument synthesized by typeclass inference which actually determines how to evaluate `c` to true or false. Write `if h : c then t else e` instead for a "dependent if-then-else" `dite`, which allows `t`/`e` to use the fact that `c` is true/false. .twiceBin.twice (a✝ : Bin) : Bin (fromNatBin.fromNat (n : Nat) : Bin (nNat / 2)) else`if c then t else e` is notation for `ite c t e`, "if-then-else", which decides to return `t` or `e` depending on whether `c` is true or false. The explicit argument `c : Prop` does not have any actual computational content, but there is an additional `[Decidable c]` argument synthesized by typeclass inference which actually determines how to evaluate `c` to true or false. Write `if h : c then t else e` instead for a "dependent if-then-else" `dite`, which allows `t`/`e` to use the fact that `c` is true/false. .succTwiceBin.succTwice (a✝ : Bin) : Bin (fromNatBin.fromNat (n : Nat) : Bin (nNat / 2))

This function terminates because nNat / 2 is less than nNat. Because omega is now used to check for decreasing arguments, this definition does not require any additional annotations or proofs.

Library Search

Lean 4.7 includes the new tactics apply? and exact? for searching for lemmas that apply to the present proof goal. Originally developed as part of Mathlib in Lean 3, these tactics migrated first to Lean 4, then to Std, and have now been upstreamed. In recent months, a new index structure has removed the need to generate separate on-disk cache, which means that they can be used for any project without any additional complication in the build system.

Both library search tactics search for a lemma that can be used in the current proof goal. exact? additionally requires that the goal be completely solved by the lemma.

When working with a very large library, this search process can take some time. That's why both tactics report their result back, and a single click can replace the call to the library search tactic with an invocation of apply or exact using the found lemma, making it fast to re-check the proof later.

This proof succeeds:

theorem map_containsmap_contains.{u_2, u_1} {α : Type u_1} {β : Type u_2} {x : α} {xs : List α} (f : α → β) (h : x ∈ xs) : f x ∈ List.map f xs {xsList α : ListList.{u} (α : Type u) : Type u`List α` is the type of ordered lists with elements of type `α`. It is implemented as a linked list. `List α` is isomorphic to `Array α`, but they are useful for different things: * `List α` is easier for reasoning, and `Array α` is modeled as a wrapper around `List α` * `List α` works well as a persistent data structure, when many copies of the tail are shared. When the value is not shared, `Array α` will have better performance because it can do destructive updates. αType u_1} (fα → β : αType u_1 βType u_2) (hx ∈ xs : xα xsList α) : fα → β xα xsList α.mapList.map.{u, v} {α : Type u} {β : Type v} (f : α → β) (a✝ : List α) : List β`O(|l|)`. `map f l` applies `f` to each element of the list. * `map f [a, b, c] = [f a, f b, f c]` fα → β :=
αType u_1:Type u_1
βType u_2:Type u_2
xα:αType u_1
xsList α:ListList.{u} (α : Type u) : Type u`List α` is the type of ordered lists with elements of type `α`. It is implemented as a linked list. `List α` is isomorphic to `Array α`, but they are useful for different things: * `List α` is easier for reasoning, and `Array α` is modeled as a wrapper around `List α` * `List α` works well as a persistent data structure, when many copies of the tail are shared. When the value is not shared, `Array α` will have better performance because it can do destructive updates. αType u_1
fα → β:αType u_1βType u_2
hx ∈ xs:xαMembership.mem.{u, v} {α : outParam (Type u)} {γ : Type v} [self : Membership α γ] (a✝ : α) (a✝¹ : γ) : PropThe membership relation `a ∈ s : Prop` where `a : α`, `s : γ`. xsList α
fα → β xαMembership.mem.{u, v} {α : outParam (Type u)} {γ : Type v} [self : Membership α γ] (a✝ : α) (a✝¹ : γ) : PropThe membership relation `a ∈ s : Prop` where `a : α`, `s : γ`. List.mapList.map.{u, v} {α : Type u} {β : Type v} (f : α → β) (a✝ : List α) : List β`O(|l|)`. `map f l` applies `f` to each element of the list. * `map f [a, b, c] = [f a, f b, f c]` fα → β xsList α
All goals completed! 🐙

In the process of succeeding, it suggests:

Try this: exact List.mem_map_of_mem f h

Clicking the message in the infoview or running the code action rewrites the proof to:

theorem map_containsmap_contains.{u_2, u_1} {α : Type u_1} {β : Type u_2} {x : α} {xs : List α} (f : α → β) (h : x ∈ xs) : f x ∈ List.map f xs {xsList α : ListList.{u} (α : Type u) : Type u`List α` is the type of ordered lists with elements of type `α`. It is implemented as a linked list. `List α` is isomorphic to `Array α`, but they are useful for different things: * `List α` is easier for reasoning, and `Array α` is modeled as a wrapper around `List α` * `List α` works well as a persistent data structure, when many copies of the tail are shared. When the value is not shared, `Array α` will have better performance because it can do destructive updates. αType u_1} (fα → β : αType u_1 βType u_2) (hx ∈ xs : xα xsList α) : fα → β xα xsList α.mapList.map.{u, v} {α : Type u} {β : Type v} (f : α → β) (a✝ : List α) : List β`O(|l|)`. `map f l` applies `f` to each element of the list. * `map f [a, b, c] = [f a, f b, f c]` fα → β :=
αType u_1:Type u_1
βType u_2:Type u_2
xα:αType u_1
xsList α:ListList.{u} (α : Type u) : Type u`List α` is the type of ordered lists with elements of type `α`. It is implemented as a linked list. `List α` is isomorphic to `Array α`, but they are useful for different things: * `List α` is easier for reasoning, and `Array α` is modeled as a wrapper around `List α` * `List α` works well as a persistent data structure, when many copies of the tail are shared. When the value is not shared, `Array α` will have better performance because it can do destructive updates. αType u_1
fα → β:αType u_1βType u_2
hx ∈ xs:xαMembership.mem.{u, v} {α : outParam (Type u)} {γ : Type v} [self : Membership α γ] (a✝ : α) (a✝¹ : γ) : PropThe membership relation `a ∈ s : Prop` where `a : α`, `s : γ`. xsList α
fα → β xαMembership.mem.{u, v} {α : outParam (Type u)} {γ : Type v} [self : Membership α γ] (a✝ : α) (a✝¹ : γ) : PropThe membership relation `a ∈ s : Prop` where `a : α`, `s : γ`. List.mapList.map.{u, v} {α : Type u} {β : Type v} (f : α → β) (a✝ : List α) : List β`O(|l|)`. `map f l` applies `f` to each element of the list. * `map f [a, b, c] = [f a, f b, f c]` fα → β xsList α
All goals completed! 🐙

The library search tactics are also useful for discovering missing assumptions. Using apply? in this example yields many suggestions:

theorem declaration uses 'sorry'mul_lt_root_.mul_lt (x y z : Nat) : x * y < x * z (xNat yNat zNat : NatNat : TypeThe type of natural numbers, starting at zero. It is defined as an inductive type freely generated by "zero is a natural number" and "the successor of a natural number is a natural number". You can prove a theorem `P n` about `n : Nat` by `induction n`, which will expect a proof of the theorem for `P 0`, and a proof of `P (succ i)` assuming a proof of `P i`. The same method also works to define functions by recursion on natural numbers: induction and recursion are two expressions of the same operation from Lean's point of view. ``` open Nat example (n : Nat) : n < succ n := by induction n with | zero => show 0 < 1 decide | succ i ih => -- ih : i < succ i show succ i < succ (succ i) exact Nat.succ_lt_succ ih ``` This type is special-cased by both the kernel and the compiler: * The type of expressions contains "`Nat` literals" as a primitive constructor, and the kernel knows how to reduce zero/succ expressions to nat literals. * If implemented naively, this type would represent a numeral `n` in unary as a linked list with `n` links, which is horribly inefficient. Instead, the runtime itself has a special representation for `Nat` which stores numbers up to 2^63 directly and larger numbers use an arbitrary precision "bignum" library (usually [GMP](https://gmplib.org/)). ) : xNat * yNat < xNat * zNat :=
xNat:NatNat : TypeThe type of natural numbers, starting at zero. It is defined as an inductive type freely generated by "zero is a natural number" and "the successor of a natural number is a natural number". You can prove a theorem `P n` about `n : Nat` by `induction n`, which will expect a proof of the theorem for `P 0`, and a proof of `P (succ i)` assuming a proof of `P i`. The same method also works to define functions by recursion on natural numbers: induction and recursion are two expressions of the same operation from Lean's point of view. ``` open Nat example (n : Nat) : n < succ n := by induction n with | zero => show 0 < 1 decide | succ i ih => -- ih : i < succ i show succ i < succ (succ i) exact Nat.succ_lt_succ ih ``` This type is special-cased by both the kernel and the compiler: * The type of expressions contains "`Nat` literals" as a primitive constructor, and the kernel knows how to reduce zero/succ expressions to nat literals. * If implemented naively, this type would represent a numeral `n` in unary as a linked list with `n` links, which is horribly inefficient. Instead, the runtime itself has a special representation for `Nat` which stores numbers up to 2^63 directly and larger numbers use an arbitrary precision "bignum" library (usually [GMP](https://gmplib.org/)).
yNat:NatNat : TypeThe type of natural numbers, starting at zero. It is defined as an inductive type freely generated by "zero is a natural number" and "the successor of a natural number is a natural number". You can prove a theorem `P n` about `n : Nat` by `induction n`, which will expect a proof of the theorem for `P 0`, and a proof of `P (succ i)` assuming a proof of `P i`. The same method also works to define functions by recursion on natural numbers: induction and recursion are two expressions of the same operation from Lean's point of view. ``` open Nat example (n : Nat) : n < succ n := by induction n with | zero => show 0 < 1 decide | succ i ih => -- ih : i < succ i show succ i < succ (succ i) exact Nat.succ_lt_succ ih ``` This type is special-cased by both the kernel and the compiler: * The type of expressions contains "`Nat` literals" as a primitive constructor, and the kernel knows how to reduce zero/succ expressions to nat literals. * If implemented naively, this type would represent a numeral `n` in unary as a linked list with `n` links, which is horribly inefficient. Instead, the runtime itself has a special representation for `Nat` which stores numbers up to 2^63 directly and larger numbers use an arbitrary precision "bignum" library (usually [GMP](https://gmplib.org/)).
zNat:NatNat : TypeThe type of natural numbers, starting at zero. It is defined as an inductive type freely generated by "zero is a natural number" and "the successor of a natural number is a natural number". You can prove a theorem `P n` about `n : Nat` by `induction n`, which will expect a proof of the theorem for `P 0`, and a proof of `P (succ i)` assuming a proof of `P i`. The same method also works to define functions by recursion on natural numbers: induction and recursion are two expressions of the same operation from Lean's point of view. ``` open Nat example (n : Nat) : n < succ n := by induction n with | zero => show 0 < 1 decide | succ i ih => -- ih : i < succ i show succ i < succ (succ i) exact Nat.succ_lt_succ ih ``` This type is special-cased by both the kernel and the compiler: * The type of expressions contains "`Nat` literals" as a primitive constructor, and the kernel knows how to reduce zero/succ expressions to nat literals. * If implemented naively, this type would represent a numeral `n` in unary as a linked list with `n` links, which is horribly inefficient. Instead, the runtime itself has a special representation for `Nat` which stores numbers up to 2^63 directly and larger numbers use an arbitrary precision "bignum" library (usually [GMP](https://gmplib.org/)).
xNat * HMul.hMul.{u, v, w} {α : Type u} {β : Type v} {γ : outParam (Type w)} [self : HMul α β γ] (a✝ : α) (a✝¹ : β) : γ`a * b` computes the product of `a` and `b`. The meaning of this notation is type-dependent. yNat < LT.lt.{u} {α : Type u} [self : LT α] (a✝a✝¹ : α) : PropThe less-than relation: `x < y` xNat * HMul.hMul.{u, v, w} {α : Type u} {β : Type v} {γ : outParam (Type w)} [self : HMul α β γ] (a✝ : α) (a✝¹ : β) : γ`a * b` computes the product of `a` and `b`. The meaning of this notation is type-dependent. zNat
All goals completed! 🐙

The first suggestion is:

Try this: refine Nat.mul_lt_mul_of_pos_left ?h ?hk

Applying this suggestion yields two further subgoals, which suggest premises to add to the theorem statement.

theorem mul_lt_root_.mul_lt (x y z : Nat) : x * y < x * z (xNat yNat zNat : NatNat : TypeThe type of natural numbers, starting at zero. It is defined as an inductive type freely generated by "zero is a natural number" and "the successor of a natural number is a natural number". You can prove a theorem `P n` about `n : Nat` by `induction n`, which will expect a proof of the theorem for `P 0`, and a proof of `P (succ i)` assuming a proof of `P i`. The same method also works to define functions by recursion on natural numbers: induction and recursion are two expressions of the same operation from Lean's point of view. ``` open Nat example (n : Nat) : n < succ n := by induction n with | zero => show 0 < 1 decide | succ i ih => -- ih : i < succ i show succ i < succ (succ i) exact Nat.succ_lt_succ ih ``` This type is special-cased by both the kernel and the compiler: * The type of expressions contains "`Nat` literals" as a primitive constructor, and the kernel knows how to reduce zero/succ expressions to nat literals. * If implemented naively, this type would represent a numeral `n` in unary as a linked list with `n` links, which is horribly inefficient. Instead, the runtime itself has a special representation for `Nat` which stores numbers up to 2^63 directly and larger numbers use an arbitrary precision "bignum" library (usually [GMP](https://gmplib.org/)). ) : xNat * yNat < xNat * zNat :=
xNat:NatNat : TypeThe type of natural numbers, starting at zero. It is defined as an inductive type freely generated by "zero is a natural number" and "the successor of a natural number is a natural number". You can prove a theorem `P n` about `n : Nat` by `induction n`, which will expect a proof of the theorem for `P 0`, and a proof of `P (succ i)` assuming a proof of `P i`. The same method also works to define functions by recursion on natural numbers: induction and recursion are two expressions of the same operation from Lean's point of view. ``` open Nat example (n : Nat) : n < succ n := by induction n with | zero => show 0 < 1 decide | succ i ih => -- ih : i < succ i show succ i < succ (succ i) exact Nat.succ_lt_succ ih ``` This type is special-cased by both the kernel and the compiler: * The type of expressions contains "`Nat` literals" as a primitive constructor, and the kernel knows how to reduce zero/succ expressions to nat literals. * If implemented naively, this type would represent a numeral `n` in unary as a linked list with `n` links, which is horribly inefficient. Instead, the runtime itself has a special representation for `Nat` which stores numbers up to 2^63 directly and larger numbers use an arbitrary precision "bignum" library (usually [GMP](https://gmplib.org/)).
yNat:NatNat : TypeThe type of natural numbers, starting at zero. It is defined as an inductive type freely generated by "zero is a natural number" and "the successor of a natural number is a natural number". You can prove a theorem `P n` about `n : Nat` by `induction n`, which will expect a proof of the theorem for `P 0`, and a proof of `P (succ i)` assuming a proof of `P i`. The same method also works to define functions by recursion on natural numbers: induction and recursion are two expressions of the same operation from Lean's point of view. ``` open Nat example (n : Nat) : n < succ n := by induction n with | zero => show 0 < 1 decide | succ i ih => -- ih : i < succ i show succ i < succ (succ i) exact Nat.succ_lt_succ ih ``` This type is special-cased by both the kernel and the compiler: * The type of expressions contains "`Nat` literals" as a primitive constructor, and the kernel knows how to reduce zero/succ expressions to nat literals. * If implemented naively, this type would represent a numeral `n` in unary as a linked list with `n` links, which is horribly inefficient. Instead, the runtime itself has a special representation for `Nat` which stores numbers up to 2^63 directly and larger numbers use an arbitrary precision "bignum" library (usually [GMP](https://gmplib.org/)).
zNat:NatNat : TypeThe type of natural numbers, starting at zero. It is defined as an inductive type freely generated by "zero is a natural number" and "the successor of a natural number is a natural number". You can prove a theorem `P n` about `n : Nat` by `induction n`, which will expect a proof of the theorem for `P 0`, and a proof of `P (succ i)` assuming a proof of `P i`. The same method also works to define functions by recursion on natural numbers: induction and recursion are two expressions of the same operation from Lean's point of view. ``` open Nat example (n : Nat) : n < succ n := by induction n with | zero => show 0 < 1 decide | succ i ih => -- ih : i < succ i show succ i < succ (succ i) exact Nat.succ_lt_succ ih ``` This type is special-cased by both the kernel and the compiler: * The type of expressions contains "`Nat` literals" as a primitive constructor, and the kernel knows how to reduce zero/succ expressions to nat literals. * If implemented naively, this type would represent a numeral `n` in unary as a linked list with `n` links, which is horribly inefficient. Instead, the runtime itself has a special representation for `Nat` which stores numbers up to 2^63 directly and larger numbers use an arbitrary precision "bignum" library (usually [GMP](https://gmplib.org/)).
xNat * HMul.hMul.{u, v, w} {α : Type u} {β : Type v} {γ : outParam (Type w)} [self : HMul α β γ] (a✝ : α) (a✝¹ : β) : γ`a * b` computes the product of `a` and `b`. The meaning of this notation is type-dependent. yNat < LT.lt.{u} {α : Type u} [self : LT α] (a✝a✝¹ : α) : PropThe less-than relation: `x < y` xNat * HMul.hMul.{u, v, w} {α : Type u} {β : Type v} {γ : outParam (Type w)} [self : HMul α β γ] (a✝ : α) (a✝¹ : β) : γ`a * b` computes the product of `a` and `b`. The meaning of this notation is type-dependent. zNat
h
xNat:NatNat : TypeThe type of natural numbers, starting at zero. It is defined as an inductive type freely generated by "zero is a natural number" and "the successor of a natural number is a natural number". You can prove a theorem `P n` about `n : Nat` by `induction n`, which will expect a proof of the theorem for `P 0`, and a proof of `P (succ i)` assuming a proof of `P i`. The same method also works to define functions by recursion on natural numbers: induction and recursion are two expressions of the same operation from Lean's point of view. ``` open Nat example (n : Nat) : n < succ n := by induction n with | zero => show 0 < 1 decide | succ i ih => -- ih : i < succ i show succ i < succ (succ i) exact Nat.succ_lt_succ ih ``` This type is special-cased by both the kernel and the compiler: * The type of expressions contains "`Nat` literals" as a primitive constructor, and the kernel knows how to reduce zero/succ expressions to nat literals. * If implemented naively, this type would represent a numeral `n` in unary as a linked list with `n` links, which is horribly inefficient. Instead, the runtime itself has a special representation for `Nat` which stores numbers up to 2^63 directly and larger numbers use an arbitrary precision "bignum" library (usually [GMP](https://gmplib.org/)).
yNat:NatNat : TypeThe type of natural numbers, starting at zero. It is defined as an inductive type freely generated by "zero is a natural number" and "the successor of a natural number is a natural number". You can prove a theorem `P n` about `n : Nat` by `induction n`, which will expect a proof of the theorem for `P 0`, and a proof of `P (succ i)` assuming a proof of `P i`. The same method also works to define functions by recursion on natural numbers: induction and recursion are two expressions of the same operation from Lean's point of view. ``` open Nat example (n : Nat) : n < succ n := by induction n with | zero => show 0 < 1 decide | succ i ih => -- ih : i < succ i show succ i < succ (succ i) exact Nat.succ_lt_succ ih ``` This type is special-cased by both the kernel and the compiler: * The type of expressions contains "`Nat` literals" as a primitive constructor, and the kernel knows how to reduce zero/succ expressions to nat literals. * If implemented naively, this type would represent a numeral `n` in unary as a linked list with `n` links, which is horribly inefficient. Instead, the runtime itself has a special representation for `Nat` which stores numbers up to 2^63 directly and larger numbers use an arbitrary precision "bignum" library (usually [GMP](https://gmplib.org/)).
zNat:NatNat : TypeThe type of natural numbers, starting at zero. It is defined as an inductive type freely generated by "zero is a natural number" and "the successor of a natural number is a natural number". You can prove a theorem `P n` about `n : Nat` by `induction n`, which will expect a proof of the theorem for `P 0`, and a proof of `P (succ i)` assuming a proof of `P i`. The same method also works to define functions by recursion on natural numbers: induction and recursion are two expressions of the same operation from Lean's point of view. ``` open Nat example (n : Nat) : n < succ n := by induction n with | zero => show 0 < 1 decide | succ i ih => -- ih : i < succ i show succ i < succ (succ i) exact Nat.succ_lt_succ ih ``` This type is special-cased by both the kernel and the compiler: * The type of expressions contains "`Nat` literals" as a primitive constructor, and the kernel knows how to reduce zero/succ expressions to nat literals. * If implemented naively, this type would represent a numeral `n` in unary as a linked list with `n` links, which is horribly inefficient. Instead, the runtime itself has a special representation for `Nat` which stores numbers up to 2^63 directly and larger numbers use an arbitrary precision "bignum" library (usually [GMP](https://gmplib.org/)).
yNat < LT.lt.{u} {α : Type u} [self : LT α] (a✝a✝¹ : α) : PropThe less-than relation: `x < y` zNat
hk
xNat:NatNat : TypeThe type of natural numbers, starting at zero. It is defined as an inductive type freely generated by "zero is a natural number" and "the successor of a natural number is a natural number". You can prove a theorem `P n` about `n : Nat` by `induction n`, which will expect a proof of the theorem for `P 0`, and a proof of `P (succ i)` assuming a proof of `P i`. The same method also works to define functions by recursion on natural numbers: induction and recursion are two expressions of the same operation from Lean's point of view. ``` open Nat example (n : Nat) : n < succ n := by induction n with | zero => show 0 < 1 decide | succ i ih => -- ih : i < succ i show succ i < succ (succ i) exact Nat.succ_lt_succ ih ``` This type is special-cased by both the kernel and the compiler: * The type of expressions contains "`Nat` literals" as a primitive constructor, and the kernel knows how to reduce zero/succ expressions to nat literals. * If implemented naively, this type would represent a numeral `n` in unary as a linked list with `n` links, which is horribly inefficient. Instead, the runtime itself has a special representation for `Nat` which stores numbers up to 2^63 directly and larger numbers use an arbitrary precision "bignum" library (usually [GMP](https://gmplib.org/)).
yNat:NatNat : TypeThe type of natural numbers, starting at zero. It is defined as an inductive type freely generated by "zero is a natural number" and "the successor of a natural number is a natural number". You can prove a theorem `P n` about `n : Nat` by `induction n`, which will expect a proof of the theorem for `P 0`, and a proof of `P (succ i)` assuming a proof of `P i`. The same method also works to define functions by recursion on natural numbers: induction and recursion are two expressions of the same operation from Lean's point of view. ``` open Nat example (n : Nat) : n < succ n := by induction n with | zero => show 0 < 1 decide | succ i ih => -- ih : i < succ i show succ i < succ (succ i) exact Nat.succ_lt_succ ih ``` This type is special-cased by both the kernel and the compiler: * The type of expressions contains "`Nat` literals" as a primitive constructor, and the kernel knows how to reduce zero/succ expressions to nat literals. * If implemented naively, this type would represent a numeral `n` in unary as a linked list with `n` links, which is horribly inefficient. Instead, the runtime itself has a special representation for `Nat` which stores numbers up to 2^63 directly and larger numbers use an arbitrary precision "bignum" library (usually [GMP](https://gmplib.org/)).
zNat:NatNat : TypeThe type of natural numbers, starting at zero. It is defined as an inductive type freely generated by "zero is a natural number" and "the successor of a natural number is a natural number". You can prove a theorem `P n` about `n : Nat` by `induction n`, which will expect a proof of the theorem for `P 0`, and a proof of `P (succ i)` assuming a proof of `P i`. The same method also works to define functions by recursion on natural numbers: induction and recursion are two expressions of the same operation from Lean's point of view. ``` open Nat example (n : Nat) : n < succ n := by induction n with | zero => show 0 < 1 decide | succ i ih => -- ih : i < succ i show succ i < succ (succ i) exact Nat.succ_lt_succ ih ``` This type is special-cased by both the kernel and the compiler: * The type of expressions contains "`Nat` literals" as a primitive constructor, and the kernel knows how to reduce zero/succ expressions to nat literals. * If implemented naively, this type would represent a numeral `n` in unary as a linked list with `n` links, which is horribly inefficient. Instead, the runtime itself has a special representation for `Nat` which stores numbers up to 2^63 directly and larger numbers use an arbitrary precision "bignum" library (usually [GMP](https://gmplib.org/)).
xNat > GT.gt.{u} {α : Type u} [inst✝ : LT α] (a b : α) : Prop`a > b` is an abbreviation for `b < a`. 0
unsolved goals
case h
x y z : Nat
⊢ y < z

case hk
x y z : Nat
⊢ x > 0

Inspired by the type-checking speedups that result from inserting the found proof into the file, the new termination_by? keyword causes Lean to offer to insert a termination measure that was found automatically into the file. If the search process takes a long time, this can speed up rebuilding the file. For example,

def ack_root_.ack (a✝a✝¹ : Nat) : Nat : NatNat : TypeThe type of natural numbers, starting at zero. It is defined as an inductive type freely generated by "zero is a natural number" and "the successor of a natural number is a natural number". You can prove a theorem `P n` about `n : Nat` by `induction n`, which will expect a proof of the theorem for `P 0`, and a proof of `P (succ i)` assuming a proof of `P i`. The same method also works to define functions by recursion on natural numbers: induction and recursion are two expressions of the same operation from Lean's point of view. ``` open Nat example (n : Nat) : n < succ n := by induction n with | zero => show 0 < 1 decide | succ i ih => -- ih : i < succ i show succ i < succ (succ i) exact Nat.succ_lt_succ ih ``` This type is special-cased by both the kernel and the compiler: * The type of expressions contains "`Nat` literals" as a primitive constructor, and the kernel knows how to reduce zero/succ expressions to nat literals. * If implemented naively, this type would represent a numeral `n` in unary as a linked list with `n` links, which is horribly inefficient. Instead, the runtime itself has a special representation for `Nat` which stores numbers up to 2^63 directly and larger numbers use an arbitrary precision "bignum" library (usually [GMP](https://gmplib.org/)). NatNat : TypeThe type of natural numbers, starting at zero. It is defined as an inductive type freely generated by "zero is a natural number" and "the successor of a natural number is a natural number". You can prove a theorem `P n` about `n : Nat` by `induction n`, which will expect a proof of the theorem for `P 0`, and a proof of `P (succ i)` assuming a proof of `P i`. The same method also works to define functions by recursion on natural numbers: induction and recursion are two expressions of the same operation from Lean's point of view. ``` open Nat example (n : Nat) : n < succ n := by induction n with | zero => show 0 < 1 decide | succ i ih => -- ih : i < succ i show succ i < succ (succ i) exact Nat.succ_lt_succ ih ``` This type is special-cased by both the kernel and the compiler: * The type of expressions contains "`Nat` literals" as a primitive constructor, and the kernel knows how to reduce zero/succ expressions to nat literals. * If implemented naively, this type would represent a numeral `n` in unary as a linked list with `n` links, which is horribly inefficient. Instead, the runtime itself has a special representation for `Nat` which stores numbers up to 2^63 directly and larger numbers use an arbitrary precision "bignum" library (usually [GMP](https://gmplib.org/)). NatNat : TypeThe type of natural numbers, starting at zero. It is defined as an inductive type freely generated by "zero is a natural number" and "the successor of a natural number is a natural number". You can prove a theorem `P n` about `n : Nat` by `induction n`, which will expect a proof of the theorem for `P 0`, and a proof of `P (succ i)` assuming a proof of `P i`. The same method also works to define functions by recursion on natural numbers: induction and recursion are two expressions of the same operation from Lean's point of view. ``` open Nat example (n : Nat) : n < succ n := by induction n with | zero => show 0 < 1 decide | succ i ih => -- ih : i < succ i show succ i < succ (succ i) exact Nat.succ_lt_succ ih ``` This type is special-cased by both the kernel and the compiler: * The type of expressions contains "`Nat` literals" as a primitive constructor, and the kernel knows how to reduce zero/succ expressions to nat literals. * If implemented naively, this type would represent a numeral `n` in unary as a linked list with `n` links, which is horribly inefficient. Instead, the runtime itself has a special representation for `Nat` which stores numbers up to 2^63 directly and larger numbers use an arbitrary precision "bignum" library (usually [GMP](https://gmplib.org/)). | 0, nNat => nNat + 1 | mNat + 1, 0 => ack_root_.ack (a✝a✝¹ : Nat) : Nat mNat 1 | mNat + 1, nNat + 1 => ack_root_.ack (a✝a✝¹ : Nat) : Nat mNat (ack_root_.ack (a✝a✝¹ : Nat) : Nat (mNat + 1) nNat) Try this: termination_by x1 x2 => (sizeOf x1, sizeOf x2)termination_by?Specify a termination argument for well-founded termination: ``` termination_by a - b ``` indicates that termination of the currently defined recursive function follows because the difference between the the arguments `a` and `b`. If the fuction takes further argument after the colon, you can name them as follows: ``` def example (a : Nat) : Nat → Nat → Nat := termination_by b c => a - b ``` If omitted, a termination argument will be inferred. If written as `termination_by?`, the inferrred termination argument will be suggested.

is accepted by Lean, which can automatically discover the necessary lexicographic order for termination checking, but it also suggests an explicit measure:

Try this: termination_by x1 x2 => (sizeOf x1, sizeOf x2)

Clicking the suggestion updates the program with the measure:

def ack_root_.ack (a✝a✝¹ : Nat) : Nat : NatNat : TypeThe type of natural numbers, starting at zero. It is defined as an inductive type freely generated by "zero is a natural number" and "the successor of a natural number is a natural number". You can prove a theorem `P n` about `n : Nat` by `induction n`, which will expect a proof of the theorem for `P 0`, and a proof of `P (succ i)` assuming a proof of `P i`. The same method also works to define functions by recursion on natural numbers: induction and recursion are two expressions of the same operation from Lean's point of view. ``` open Nat example (n : Nat) : n < succ n := by induction n with | zero => show 0 < 1 decide | succ i ih => -- ih : i < succ i show succ i < succ (succ i) exact Nat.succ_lt_succ ih ``` This type is special-cased by both the kernel and the compiler: * The type of expressions contains "`Nat` literals" as a primitive constructor, and the kernel knows how to reduce zero/succ expressions to nat literals. * If implemented naively, this type would represent a numeral `n` in unary as a linked list with `n` links, which is horribly inefficient. Instead, the runtime itself has a special representation for `Nat` which stores numbers up to 2^63 directly and larger numbers use an arbitrary precision "bignum" library (usually [GMP](https://gmplib.org/)). NatNat : TypeThe type of natural numbers, starting at zero. It is defined as an inductive type freely generated by "zero is a natural number" and "the successor of a natural number is a natural number". You can prove a theorem `P n` about `n : Nat` by `induction n`, which will expect a proof of the theorem for `P 0`, and a proof of `P (succ i)` assuming a proof of `P i`. The same method also works to define functions by recursion on natural numbers: induction and recursion are two expressions of the same operation from Lean's point of view. ``` open Nat example (n : Nat) : n < succ n := by induction n with | zero => show 0 < 1 decide | succ i ih => -- ih : i < succ i show succ i < succ (succ i) exact Nat.succ_lt_succ ih ``` This type is special-cased by both the kernel and the compiler: * The type of expressions contains "`Nat` literals" as a primitive constructor, and the kernel knows how to reduce zero/succ expressions to nat literals. * If implemented naively, this type would represent a numeral `n` in unary as a linked list with `n` links, which is horribly inefficient. Instead, the runtime itself has a special representation for `Nat` which stores numbers up to 2^63 directly and larger numbers use an arbitrary precision "bignum" library (usually [GMP](https://gmplib.org/)). NatNat : TypeThe type of natural numbers, starting at zero. It is defined as an inductive type freely generated by "zero is a natural number" and "the successor of a natural number is a natural number". You can prove a theorem `P n` about `n : Nat` by `induction n`, which will expect a proof of the theorem for `P 0`, and a proof of `P (succ i)` assuming a proof of `P i`. The same method also works to define functions by recursion on natural numbers: induction and recursion are two expressions of the same operation from Lean's point of view. ``` open Nat example (n : Nat) : n < succ n := by induction n with | zero => show 0 < 1 decide | succ i ih => -- ih : i < succ i show succ i < succ (succ i) exact Nat.succ_lt_succ ih ``` This type is special-cased by both the kernel and the compiler: * The type of expressions contains "`Nat` literals" as a primitive constructor, and the kernel knows how to reduce zero/succ expressions to nat literals. * If implemented naively, this type would represent a numeral `n` in unary as a linked list with `n` links, which is horribly inefficient. Instead, the runtime itself has a special representation for `Nat` which stores numbers up to 2^63 directly and larger numbers use an arbitrary precision "bignum" library (usually [GMP](https://gmplib.org/)). | 0, nNat => nNat + 1 | mNat + 1, 0 => ack_root_.ack (a✝a✝¹ : Nat) : Nat mNat 1 | mNat + 1, nNat + 1 => ack_root_.ack (a✝a✝¹ : Nat) : Nat mNat (ack_root_.ack (a✝a✝¹ : Nat) : Nat (mNat + 1) nNat) termination_bySpecify a termination argument for well-founded termination: ``` termination_by a - b ``` indicates that termination of the currently defined recursive function follows because the difference between the the arguments `a` and `b`. If the fuction takes further argument after the colon, you can name them as follows: ``` def example (a : Nat) : Nat → Nat → Nat := termination_by b c => a - b ``` If omitted, a termination argument will be inferred. If written as `termination_by?`, the inferrred termination argument will be suggested. x1 x2 => (sizeOfSizeOf.sizeOf.{u} {α : Sort u} [self : SizeOf α] (a✝ : α) : NatThe "size" of an element, a natural number which decreases on fields of each inductive type. x1Nat, sizeOfSizeOf.sizeOf.{u} {α : Sort u} [self : SizeOf α] (a✝ : α) : NatThe "size" of an element, a natural number which decreases on fields of each inductive type. x2Nat)

Further Tactics

In addition to omega and the library search tactics, a number of generally-useful tactics from Std and Mathlib are now a core part of Lean, available without imports to all users.

Recursive Case Analysis

The rcases tactic recursively case-splits a hypothesis, driven by a pattern written in a concise DSL that's inspired by Coq's intro patterns. This tactic was written by Mario Carneiro. Individual hypotheses to extract from one case are provided in angle brackets ( and ), and patterns that describe cases are separated by vertical bars (|). For example, angle brackets are useful for splitting a nested conjunction:

theorem test_root_.test {p1 p2 p3 : Prop} (h : p1 ∧ p2 ∧ p3) : p3 ∧ p2 ∧ p1 (hp1 ∧ p2 ∧ p3 : p1Prop p2Prop p3Prop) : p3Prop p2Prop p1Prop :=
p1Prop:Prop
p2Prop:Prop
p3Prop:Prop
hp1 ∧ p2 ∧ p3:p1PropAnd (a b : Prop) : Prop`And a b`, or `a ∧ b`, is the conjunction of propositions. It can be constructed and destructed like a pair: if `ha : a` and `hb : b` then `⟨ha, hb⟩ : a ∧ b`, and if `h : a ∧ b` then `h.left : a` and `h.right : b`. p2PropAnd (a b : Prop) : Prop`And a b`, or `a ∧ b`, is the conjunction of propositions. It can be constructed and destructed like a pair: if `ha : a` and `hb : b` then `⟨ha, hb⟩ : a ∧ b`, and if `h : a ∧ b` then `h.left : a` and `h.right : b`. p3Prop
p3PropAnd (a b : Prop) : Prop`And a b`, or `a ∧ b`, is the conjunction of propositions. It can be constructed and destructed like a pair: if `ha : a` and `hb : b` then `⟨ha, hb⟩ : a ∧ b`, and if `h : a ∧ b` then `h.left : a` and `h.right : b`. p2PropAnd (a b : Prop) : Prop`And a b`, or `a ∧ b`, is the conjunction of propositions. It can be constructed and destructed like a pair: if `ha : a` and `hb : b` then `⟨ha, hb⟩ : a ∧ b`, and if `h : a ∧ b` then `h.left : a` and `h.right : b`. p1Prop
intro.intro
p1Prop:Prop
p2Prop:Prop
p3Prop:Prop
h1p1:p1Prop
h2p2:p2Prop
h3p3:p3Prop
p3PropAnd (a b : Prop) : Prop`And a b`, or `a ∧ b`, is the conjunction of propositions. It can be constructed and destructed like a pair: if `ha : a` and `hb : b` then `⟨ha, hb⟩ : a ∧ b`, and if `h : a ∧ b` then `h.left : a` and `h.right : b`. p2PropAnd (a b : Prop) : Prop`And a b`, or `a ∧ b`, is the conjunction of propositions. It can be constructed and destructed like a pair: if `ha : a` and `hb : b` then `⟨ha, hb⟩ : a ∧ b`, and if `h : a ∧ b` then `h.left : a` and `h.right : b`. p1Prop
unsolved goals
case intro.intro
p1 p2 p3 : Prop
h1 : p1
h2 : p2
h3 : p3
⊢ p3 ∧ p2 ∧ p1

Vertical bars are useful for naming nested disjuncts:

theorem test_root_.test {p1 p2 p3 : Prop} (h : p1 ∨ p2 ∨ p3) : p3 ∨ p2 ∨ p1 (hp1 ∨ p2 ∨ p3 : p1Prop p2Prop p3Prop) : p3Prop p2Prop p1Prop :=
p1Prop:Prop
p2Prop:Prop
p3Prop:Prop
hp1 ∨ p2 ∨ p3:p1PropOr (a b : Prop) : Prop`Or a b`, or `a ∨ b`, is the disjunction of propositions. There are two constructors for `Or`, called `Or.inl : a → a ∨ b` and `Or.inr : b → a ∨ b`, and you can use `match` or `cases` to destruct an `Or` assumption into the two cases. p2PropOr (a b : Prop) : Prop`Or a b`, or `a ∨ b`, is the disjunction of propositions. There are two constructors for `Or`, called `Or.inl : a → a ∨ b` and `Or.inr : b → a ∨ b`, and you can use `match` or `cases` to destruct an `Or` assumption into the two cases. p3Prop
p3PropOr (a b : Prop) : Prop`Or a b`, or `a ∨ b`, is the disjunction of propositions. There are two constructors for `Or`, called `Or.inl : a → a ∨ b` and `Or.inr : b → a ∨ b`, and you can use `match` or `cases` to destruct an `Or` assumption into the two cases. p2PropOr (a b : Prop) : Prop`Or a b`, or `a ∨ b`, is the disjunction of propositions. There are two constructors for `Or`, called `Or.inl : a → a ∨ b` and `Or.inr : b → a ∨ b`, and you can use `match` or `cases` to destruct an `Or` assumption into the two cases. p1Prop
inl
p1Prop:Prop
p2Prop:Prop
p3Prop:Prop
h1p1:p1Prop
p3PropOr (a b : Prop) : Prop`Or a b`, or `a ∨ b`, is the disjunction of propositions. There are two constructors for `Or`, called `Or.inl : a → a ∨ b` and `Or.inr : b → a ∨ b`, and you can use `match` or `cases` to destruct an `Or` assumption into the two cases. p2PropOr (a b : Prop) : Prop`Or a b`, or `a ∨ b`, is the disjunction of propositions. There are two constructors for `Or`, called `Or.inl : a → a ∨ b` and `Or.inr : b → a ∨ b`, and you can use `match` or `cases` to destruct an `Or` assumption into the two cases. p1Prop
inr.inl
p1Prop:Prop
p2Prop:Prop
p3Prop:Prop
h2p2:p2Prop
p3PropOr (a b : Prop) : Prop`Or a b`, or `a ∨ b`, is the disjunction of propositions. There are two constructors for `Or`, called `Or.inl : a → a ∨ b` and `Or.inr : b → a ∨ b`, and you can use `match` or `cases` to destruct an `Or` assumption into the two cases. p2PropOr (a b : Prop) : Prop`Or a b`, or `a ∨ b`, is the disjunction of propositions. There are two constructors for `Or`, called `Or.inl : a → a ∨ b` and `Or.inr : b → a ∨ b`, and you can use `match` or `cases` to destruct an `Or` assumption into the two cases. p1Prop
inr.inr
p1Prop:Prop
p2Prop:Prop
p3Prop:Prop
h3p3:p3Prop
p3PropOr (a b : Prop) : Prop`Or a b`, or `a ∨ b`, is the disjunction of propositions. There are two constructors for `Or`, called `Or.inl : a → a ∨ b` and `Or.inr : b → a ∨ b`, and you can use `match` or `cases` to destruct an `Or` assumption into the two cases. p2PropOr (a b : Prop) : Prop`Or a b`, or `a ∨ b`, is the disjunction of propositions. There are two constructors for `Or`, called `Or.inl : a → a ∨ b` and `Or.inr : b → a ∨ b`, and you can use `match` or `cases` to destruct an `Or` assumption into the two cases. p1Prop
unsolved goals
case inl
p1 p2 p3 : Prop
h1 : p1
⊢ p3 ∨ p2 ∨ p1

case inr.inl
p1 p2 p3 : Prop
h2 : p2
⊢ p3 ∨ p2 ∨ p1

case inr.inr
p1 p2 p3 : Prop
h3 : p3
⊢ p3 ∨ p2 ∨ p1

The patterns compose as well:

theorem test_root_.test {p1 p2 p3 p4 : Prop} (h : p1 ∨ p2 ∧ p3 ∨ p4) : p4 ∨ p2 ∧ p1 (hp1 ∨ p2 ∧ p3 ∨ p4 : p1Prop (p2Prop p3Prop) p4Prop) : p4Prop p2Prop p1Prop :=
p1Prop:Prop
p2Prop:Prop
p3Prop:Prop
p4Prop:Prop
hp1 ∨ p2 ∧ p3 ∨ p4:p1PropOr (a b : Prop) : Prop`Or a b`, or `a ∨ b`, is the disjunction of propositions. There are two constructors for `Or`, called `Or.inl : a → a ∨ b` and `Or.inr : b → a ∨ b`, and you can use `match` or `cases` to destruct an `Or` assumption into the two cases. p2PropAnd (a b : Prop) : Prop`And a b`, or `a ∧ b`, is the conjunction of propositions. It can be constructed and destructed like a pair: if `ha : a` and `hb : b` then `⟨ha, hb⟩ : a ∧ b`, and if `h : a ∧ b` then `h.left : a` and `h.right : b`. p3PropOr (a b : Prop) : Prop`Or a b`, or `a ∨ b`, is the disjunction of propositions. There are two constructors for `Or`, called `Or.inl : a → a ∨ b` and `Or.inr : b → a ∨ b`, and you can use `match` or `cases` to destruct an `Or` assumption into the two cases. p4Prop
p4PropOr (a b : Prop) : Prop`Or a b`, or `a ∨ b`, is the disjunction of propositions. There are two constructors for `Or`, called `Or.inl : a → a ∨ b` and `Or.inr : b → a ∨ b`, and you can use `match` or `cases` to destruct an `Or` assumption into the two cases. p2PropAnd (a b : Prop) : Prop`And a b`, or `a ∧ b`, is the conjunction of propositions. It can be constructed and destructed like a pair: if `ha : a` and `hb : b` then `⟨ha, hb⟩ : a ∧ b`, and if `h : a ∧ b` then `h.left : a` and `h.right : b`. p1Prop
inl
p1Prop:Prop
p2Prop:Prop
p3Prop:Prop
p4Prop:Prop
h1p1:p1Prop
p4PropOr (a b : Prop) : Prop`Or a b`, or `a ∨ b`, is the disjunction of propositions. There are two constructors for `Or`, called `Or.inl : a → a ∨ b` and `Or.inr : b → a ∨ b`, and you can use `match` or `cases` to destruct an `Or` assumption into the two cases. p2PropAnd (a b : Prop) : Prop`And a b`, or `a ∧ b`, is the conjunction of propositions. It can be constructed and destructed like a pair: if `ha : a` and `hb : b` then `⟨ha, hb⟩ : a ∧ b`, and if `h : a ∧ b` then `h.left : a` and `h.right : b`. p1Prop
inr.inl.intro
p1Prop:Prop
p2Prop:Prop
p3Prop:Prop
p4Prop:Prop
h2p2:p2Prop
h3p3:p3Prop
p4PropOr (a b : Prop) : Prop`Or a b`, or `a ∨ b`, is the disjunction of propositions. There are two constructors for `Or`, called `Or.inl : a → a ∨ b` and `Or.inr : b → a ∨ b`, and you can use `match` or `cases` to destruct an `Or` assumption into the two cases. p2PropAnd (a b : Prop) : Prop`And a b`, or `a ∧ b`, is the conjunction of propositions. It can be constructed and destructed like a pair: if `ha : a` and `hb : b` then `⟨ha, hb⟩ : a ∧ b`, and if `h : a ∧ b` then `h.left : a` and `h.right : b`. p1Prop
inr.inr
p1Prop:Prop
p2Prop:Prop
p3Prop:Prop
p4Prop:Prop
h4p4:p4Prop
p4PropOr (a b : Prop) : Prop`Or a b`, or `a ∨ b`, is the disjunction of propositions. There are two constructors for `Or`, called `Or.inl : a → a ∨ b` and `Or.inr : b → a ∨ b`, and you can use `match` or `cases` to destruct an `Or` assumption into the two cases. p2PropAnd (a b : Prop) : Prop`And a b`, or `a ∧ b`, is the conjunction of propositions. It can be constructed and destructed like a pair: if `ha : a` and `hb : b` then `⟨ha, hb⟩ : a ∧ b`, and if `h : a ∧ b` then `h.left : a` and `h.right : b`. p1Prop
unsolved goals
case inl
p1 p2 p3 p4 : Prop
h1 : p1
⊢ p4 ∨ p2 ∧ p1

case inr.inl.intro
p1 p2 p3 p4 : Prop
h2 : p2
h3 : p3
⊢ p4 ∨ p2 ∧ p1

case inr.inr
p1 p2 p3 p4 : Prop
h4 : p4
⊢ p4 ∨ p2 ∧ p1

One common use of angle brackets in rcases is to destructure existentials, bringing both the witness and the proof into scope. In this proof that every number is either even or odd, rcases both splits the disjunction in the induction hypothesis and introduces the existential witnesses and proofs:

theorem even_or_odd_root_.even_or_odd (n : Nat) : (∃ half, n = 2 * half) ∨ ∃ half, n = 2 * half + 1 (nNat : NatNat : TypeThe type of natural numbers, starting at zero. It is defined as an inductive type freely generated by "zero is a natural number" and "the successor of a natural number is a natural number". You can prove a theorem `P n` about `n : Nat` by `induction n`, which will expect a proof of the theorem for `P 0`, and a proof of `P (succ i)` assuming a proof of `P i`. The same method also works to define functions by recursion on natural numbers: induction and recursion are two expressions of the same operation from Lean's point of view. ``` open Nat example (n : Nat) : n < succ n := by induction n with | zero => show 0 < 1 decide | succ i ih => -- ih : i < succ i show succ i < succ (succ i) exact Nat.succ_lt_succ ih ``` This type is special-cased by both the kernel and the compiler: * The type of expressions contains "`Nat` literals" as a primitive constructor, and the kernel knows how to reduce zero/succ expressions to nat literals. * If implemented naively, this type would represent a numeral `n` in unary as a linked list with `n` links, which is horribly inefficient. Instead, the runtime itself has a special representation for `Nat` which stores numbers up to 2^63 directly and larger numbers use an arbitrary precision "bignum" library (usually [GMP](https://gmplib.org/)). ) : ( halfNat, nNat = 2 * halfNat) ( halfNat, nNat = 2 * halfNat + 1) :=
nNat:NatNat : TypeThe type of natural numbers, starting at zero. It is defined as an inductive type freely generated by "zero is a natural number" and "the successor of a natural number is a natural number". You can prove a theorem `P n` about `n : Nat` by `induction n`, which will expect a proof of the theorem for `P 0`, and a proof of `P (succ i)` assuming a proof of `P i`. The same method also works to define functions by recursion on natural numbers: induction and recursion are two expressions of the same operation from Lean's point of view. ``` open Nat example (n : Nat) : n < succ n := by induction n with | zero => show 0 < 1 decide | succ i ih => -- ih : i < succ i show succ i < succ (succ i) exact Nat.succ_lt_succ ih ``` This type is special-cased by both the kernel and the compiler: * The type of expressions contains "`Nat` literals" as a primitive constructor, and the kernel knows how to reduce zero/succ expressions to nat literals. * If implemented naively, this type would represent a numeral `n` in unary as a linked list with `n` links, which is horribly inefficient. Instead, the runtime itself has a special representation for `Nat` which stores numbers up to 2^63 directly and larger numbers use an arbitrary precision "bignum" library (usually [GMP](https://gmplib.org/)).
(∃ half, nNat = Eq.{u_1} {α : Sort u_1} (a✝a✝¹ : α) : PropThe equality relation. It has one introduction rule, `Eq.refl`. We use `a = b` as notation for `Eq a b`. A fundamental property of equality is that it is an equivalence relation. ``` variable (α : Type) (a b c d : α) variable (hab : a = b) (hcb : c = b) (hcd : c = d) example : a = d := Eq.trans (Eq.trans hab (Eq.symm hcb)) hcd ``` Equality is much more than an equivalence relation, however. It has the important property that every assertion respects the equivalence, in the sense that we can substitute equal expressions without changing the truth value. That is, given `h1 : a = b` and `h2 : p a`, we can construct a proof for `p b` using substitution: `Eq.subst h1 h2`. Example: ``` example (α : Type) (a b : α) (p : α → Prop) (h1 : a = b) (h2 : p a) : p b := Eq.subst h1 h2 example (α : Type) (a b : α) (p : α → Prop) (h1 : a = b) (h2 : p a) : p b := h1 ▸ h2 ``` The triangle in the second presentation is a macro built on top of `Eq.subst` and `Eq.symm`, and you can enter it by typing `\t`. For more information: [Equality](https://lean-lang.org/theorem_proving_in_lean4/quantifiers_and_equality.html#equality) 2 * HMul.hMul.{u, v, w} {α : Type u} {β : Type v} {γ : outParam (Type w)} [self : HMul α β γ] (a✝ : α) (a✝¹ : β) : γ`a * b` computes the product of `a` and `b`. The meaning of this notation is type-dependent. halfNat)Or (a b : Prop) : Prop`Or a b`, or `a ∨ b`, is the disjunction of propositions. There are two constructors for `Or`, called `Or.inl : a → a ∨ b` and `Or.inr : b → a ∨ b`, and you can use `match` or `cases` to destruct an `Or` assumption into the two cases. ∃ half, nNat = Eq.{u_1} {α : Sort u_1} (a✝a✝¹ : α) : PropThe equality relation. It has one introduction rule, `Eq.refl`. We use `a = b` as notation for `Eq a b`. A fundamental property of equality is that it is an equivalence relation. ``` variable (α : Type) (a b c d : α) variable (hab : a = b) (hcb : c = b) (hcd : c = d) example : a = d := Eq.trans (Eq.trans hab (Eq.symm hcb)) hcd ``` Equality is much more than an equivalence relation, however. It has the important property that every assertion respects the equivalence, in the sense that we can substitute equal expressions without changing the truth value. That is, given `h1 : a = b` and `h2 : p a`, we can construct a proof for `p b` using substitution: `Eq.subst h1 h2`. Example: ``` example (α : Type) (a b : α) (p : α → Prop) (h1 : a = b) (h2 : p a) : p b := Eq.subst h1 h2 example (α : Type) (a b : α) (p : α → Prop) (h1 : a = b) (h2 : p a) : p b := h1 ▸ h2 ``` The triangle in the second presentation is a macro built on top of `Eq.subst` and `Eq.symm`, and you can enter it by typing `\t`. For more information: [Equality](https://lean-lang.org/theorem_proving_in_lean4/quantifiers_and_equality.html#equality) 2 * HMul.hMul.{u, v, w} {α : Type u} {β : Type v} {γ : outParam (Type w)} [self : HMul α β γ] (a✝ : α) (a✝¹ : β) : γ`a * b` computes the product of `a` and `b`. The meaning of this notation is type-dependent. halfNat + HAdd.hAdd.{u, v, w} {α : Type u} {β : Type v} {γ : outParam (Type w)} [self : HAdd α β γ] (a✝ : α) (a✝¹ : β) : γ`a + b` computes the sum of `a` and `b`. The meaning of this notation is type-dependent. 1
inductionAssuming `x` is a variable in the local context with an inductive type, `induction x` applies induction on `x` to the main goal, producing one goal for each constructor of the inductive type, in which the target is replaced by a general instance of that constructor and an inductive hypothesis is added for each recursive argument to the constructor. If the type of an element in the local context depends on `x`, that element is reverted and reintroduced afterward, so that the inductive hypothesis incorporates that hypothesis as well. For example, given `n : Nat` and a goal with a hypothesis `h : P n` and target `Q n`, `induction n` produces one goal with hypothesis `h : P 0` and target `Q 0`, and one goal with hypotheses `h : P (Nat.succ a)` and `ih₁ : P a → Q a` and target `Q (Nat.succ a)`. Here the names `a` and `ih₁` are chosen automatically and are not accessible. You can use `with` to provide the variables names for each constructor. - `induction e`, where `e` is an expression instead of a variable, generalizes `e` in the goal, and then performs induction on the resulting variable. - `induction e using r` allows the user to specify the principle of induction that should be used. Here `r` should be a term whose result type must be of the form `C t`, where `C` is a bound variable and `t` is a (possibly empty) sequence of bound variables - `induction e generalizing z₁ ... zₙ`, where `z₁ ... zₙ` are variables in the local context, generalizes over `z₁ ... zₙ` before applying the induction but then introduces them in each goal. In other words, the net effect is that each inductive hypothesis is generalized. - Given `x : Nat`, `induction x with | zero => tac₁ | succ x' ih => tac₂` uses tactic `tac₁` for the `zero` case, and `tac₂` for the `succ` case. nNat withAfter `with`, there is an optional tactic that runs on all branches, and then a list of alternatives. | zeroNat.zero : Nat`Nat.zero`, normally written `0 : Nat`, is the smallest natural number. This is one of the two constructors of `Nat`.
zero(∃ half, Nat.zeroNat.zero : Nat`Nat.zero`, normally written `0 : Nat`, is the smallest natural number. This is one of the two constructors of `Nat`. = Eq.{u_1} {α : Sort u_1} (a✝a✝¹ : α) : PropThe equality relation. It has one introduction rule, `Eq.refl`. We use `a = b` as notation for `Eq a b`. A fundamental property of equality is that it is an equivalence relation. ``` variable (α : Type) (a b c d : α) variable (hab : a = b) (hcb : c = b) (hcd : c = d) example : a = d := Eq.trans (Eq.trans hab (Eq.symm hcb)) hcd ``` Equality is much more than an equivalence relation, however. It has the important property that every assertion respects the equivalence, in the sense that we can substitute equal expressions without changing the truth value. That is, given `h1 : a = b` and `h2 : p a`, we can construct a proof for `p b` using substitution: `Eq.subst h1 h2`. Example: ``` example (α : Type) (a b : α) (p : α → Prop) (h1 : a = b) (h2 : p a) : p b := Eq.subst h1 h2 example (α : Type) (a b : α) (p : α → Prop) (h1 : a = b) (h2 : p a) : p b := h1 ▸ h2 ``` The triangle in the second presentation is a macro built on top of `Eq.subst` and `Eq.symm`, and you can enter it by typing `\t`. For more information: [Equality](https://lean-lang.org/theorem_proving_in_lean4/quantifiers_and_equality.html#equality) 2 * HMul.hMul.{u, v, w} {α : Type u} {β : Type v} {γ : outParam (Type w)} [self : HMul α β γ] (a✝ : α) (a✝¹ : β) : γ`a * b` computes the product of `a` and `b`. The meaning of this notation is type-dependent. halfNat)Or (a b : Prop) : Prop`Or a b`, or `a ∨ b`, is the disjunction of propositions. There are two constructors for `Or`, called `Or.inl : a → a ∨ b` and `Or.inr : b → a ∨ b`, and you can use `match` or `cases` to destruct an `Or` assumption into the two cases. ∃ half, Nat.zeroNat.zero : Nat`Nat.zero`, normally written `0 : Nat`, is the smallest natural number. This is one of the two constructors of `Nat`. = Eq.{u_1} {α : Sort u_1} (a✝a✝¹ : α) : PropThe equality relation. It has one introduction rule, `Eq.refl`. We use `a = b` as notation for `Eq a b`. A fundamental property of equality is that it is an equivalence relation. ``` variable (α : Type) (a b c d : α) variable (hab : a = b) (hcb : c = b) (hcd : c = d) example : a = d := Eq.trans (Eq.trans hab (Eq.symm hcb)) hcd ``` Equality is much more than an equivalence relation, however. It has the important property that every assertion respects the equivalence, in the sense that we can substitute equal expressions without changing the truth value. That is, given `h1 : a = b` and `h2 : p a`, we can construct a proof for `p b` using substitution: `Eq.subst h1 h2`. Example: ``` example (α : Type) (a b : α) (p : α → Prop) (h1 : a = b) (h2 : p a) : p b := Eq.subst h1 h2 example (α : Type) (a b : α) (p : α → Prop) (h1 : a = b) (h2 : p a) : p b := h1 ▸ h2 ``` The triangle in the second presentation is a macro built on top of `Eq.subst` and `Eq.symm`, and you can enter it by typing `\t`. For more information: [Equality](https://lean-lang.org/theorem_proving_in_lean4/quantifiers_and_equality.html#equality) 2 * HMul.hMul.{u, v, w} {α : Type u} {β : Type v} {γ : outParam (Type w)} [self : HMul α β γ] (a✝ : α) (a✝¹ : β) : γ`a * b` computes the product of `a` and `b`. The meaning of this notation is type-dependent. halfNat + HAdd.hAdd.{u, v, w} {α : Type u} {β : Type v} {γ : outParam (Type w)} [self : HAdd α β γ] (a✝ : α) (a✝¹ : β) : γ`a + b` computes the sum of `a` and `b`. The meaning of this notation is type-dependent. 1
zero.h∃ half, Nat.zeroNat.zero : Nat`Nat.zero`, normally written `0 : Nat`, is the smallest natural number. This is one of the two constructors of `Nat`. = Eq.{u_1} {α : Sort u_1} (a✝a✝¹ : α) : PropThe equality relation. It has one introduction rule, `Eq.refl`. We use `a = b` as notation for `Eq a b`. A fundamental property of equality is that it is an equivalence relation. ``` variable (α : Type) (a b c d : α) variable (hab : a = b) (hcb : c = b) (hcd : c = d) example : a = d := Eq.trans (Eq.trans hab (Eq.symm hcb)) hcd ``` Equality is much more than an equivalence relation, however. It has the important property that every assertion respects the equivalence, in the sense that we can substitute equal expressions without changing the truth value. That is, given `h1 : a = b` and `h2 : p a`, we can construct a proof for `p b` using substitution: `Eq.subst h1 h2`. Example: ``` example (α : Type) (a b : α) (p : α → Prop) (h1 : a = b) (h2 : p a) : p b := Eq.subst h1 h2 example (α : Type) (a b : α) (p : α → Prop) (h1 : a = b) (h2 : p a) : p b := h1 ▸ h2 ``` The triangle in the second presentation is a macro built on top of `Eq.subst` and `Eq.symm`, and you can enter it by typing `\t`. For more information: [Equality](https://lean-lang.org/theorem_proving_in_lean4/quantifiers_and_equality.html#equality) 2 * HMul.hMul.{u, v, w} {α : Type u} {β : Type v} {γ : outParam (Type w)} [self : HMul α β γ] (a✝ : α) (a✝¹ : β) : γ`a * b` computes the product of `a` and `b`. The meaning of this notation is type-dependent. halfNat
;
All goals completed! 🐙
| succNat.succ (n : Nat) : NatThe successor function on natural numbers, `succ n = n + 1`. This is one of the two constructors of `Nat`. n'Nat ih(∃ half, n' = 2 * half) ∨ ∃ half, n' = 2 * half + 1
succ
n'Nat:NatNat : TypeThe type of natural numbers, starting at zero. It is defined as an inductive type freely generated by "zero is a natural number" and "the successor of a natural number is a natural number". You can prove a theorem `P n` about `n : Nat` by `induction n`, which will expect a proof of the theorem for `P 0`, and a proof of `P (succ i)` assuming a proof of `P i`. The same method also works to define functions by recursion on natural numbers: induction and recursion are two expressions of the same operation from Lean's point of view. ``` open Nat example (n : Nat) : n < succ n := by induction n with | zero => show 0 < 1 decide | succ i ih => -- ih : i < succ i show succ i < succ (succ i) exact Nat.succ_lt_succ ih ``` This type is special-cased by both the kernel and the compiler: * The type of expressions contains "`Nat` literals" as a primitive constructor, and the kernel knows how to reduce zero/succ expressions to nat literals. * If implemented naively, this type would represent a numeral `n` in unary as a linked list with `n` links, which is horribly inefficient. Instead, the runtime itself has a special representation for `Nat` which stores numbers up to 2^63 directly and larger numbers use an arbitrary precision "bignum" library (usually [GMP](https://gmplib.org/)).
ih(∃ half, n' = 2 * half) ∨ ∃ half, n' = 2 * half + 1:(∃ half, n'Nat = Eq.{u_1} {α : Sort u_1} (a✝a✝¹ : α) : PropThe equality relation. It has one introduction rule, `Eq.refl`. We use `a = b` as notation for `Eq a b`. A fundamental property of equality is that it is an equivalence relation. ``` variable (α : Type) (a b c d : α) variable (hab : a = b) (hcb : c = b) (hcd : c = d) example : a = d := Eq.trans (Eq.trans hab (Eq.symm hcb)) hcd ``` Equality is much more than an equivalence relation, however. It has the important property that every assertion respects the equivalence, in the sense that we can substitute equal expressions without changing the truth value. That is, given `h1 : a = b` and `h2 : p a`, we can construct a proof for `p b` using substitution: `Eq.subst h1 h2`. Example: ``` example (α : Type) (a b : α) (p : α → Prop) (h1 : a = b) (h2 : p a) : p b := Eq.subst h1 h2 example (α : Type) (a b : α) (p : α → Prop) (h1 : a = b) (h2 : p a) : p b := h1 ▸ h2 ``` The triangle in the second presentation is a macro built on top of `Eq.subst` and `Eq.symm`, and you can enter it by typing `\t`. For more information: [Equality](https://lean-lang.org/theorem_proving_in_lean4/quantifiers_and_equality.html#equality) 2 * HMul.hMul.{u, v, w} {α : Type u} {β : Type v} {γ : outParam (Type w)} [self : HMul α β γ] (a✝ : α) (a✝¹ : β) : γ`a * b` computes the product of `a` and `b`. The meaning of this notation is type-dependent. halfNat)Or (a b : Prop) : Prop`Or a b`, or `a ∨ b`, is the disjunction of propositions. There are two constructors for `Or`, called `Or.inl : a → a ∨ b` and `Or.inr : b → a ∨ b`, and you can use `match` or `cases` to destruct an `Or` assumption into the two cases. ∃ half, n'Nat = Eq.{u_1} {α : Sort u_1} (a✝a✝¹ : α) : PropThe equality relation. It has one introduction rule, `Eq.refl`. We use `a = b` as notation for `Eq a b`. A fundamental property of equality is that it is an equivalence relation. ``` variable (α : Type) (a b c d : α) variable (hab : a = b) (hcb : c = b) (hcd : c = d) example : a = d := Eq.trans (Eq.trans hab (Eq.symm hcb)) hcd ``` Equality is much more than an equivalence relation, however. It has the important property that every assertion respects the equivalence, in the sense that we can substitute equal expressions without changing the truth value. That is, given `h1 : a = b` and `h2 : p a`, we can construct a proof for `p b` using substitution: `Eq.subst h1 h2`. Example: ``` example (α : Type) (a b : α) (p : α → Prop) (h1 : a = b) (h2 : p a) : p b := Eq.subst h1 h2 example (α : Type) (a b : α) (p : α → Prop) (h1 : a = b) (h2 : p a) : p b := h1 ▸ h2 ``` The triangle in the second presentation is a macro built on top of `Eq.subst` and `Eq.symm`, and you can enter it by typing `\t`. For more information: [Equality](https://lean-lang.org/theorem_proving_in_lean4/quantifiers_and_equality.html#equality) 2 * HMul.hMul.{u, v, w} {α : Type u} {β : Type v} {γ : outParam (Type w)} [self : HMul α β γ] (a✝ : α) (a✝¹ : β) : γ`a * b` computes the product of `a` and `b`. The meaning of this notation is type-dependent. halfNat + HAdd.hAdd.{u, v, w} {α : Type u} {β : Type v} {γ : outParam (Type w)} [self : HAdd α β γ] (a✝ : α) (a✝¹ : β) : γ`a + b` computes the sum of `a` and `b`. The meaning of this notation is type-dependent. 1
(∃ half, Nat.succNat.succ (n : Nat) : NatThe successor function on natural numbers, `succ n = n + 1`. This is one of the two constructors of `Nat`. n'Nat = Eq.{u_1} {α : Sort u_1} (a✝a✝¹ : α) : PropThe equality relation. It has one introduction rule, `Eq.refl`. We use `a = b` as notation for `Eq a b`. A fundamental property of equality is that it is an equivalence relation. ``` variable (α : Type) (a b c d : α) variable (hab : a = b) (hcb : c = b) (hcd : c = d) example : a = d := Eq.trans (Eq.trans hab (Eq.symm hcb)) hcd ``` Equality is much more than an equivalence relation, however. It has the important property that every assertion respects the equivalence, in the sense that we can substitute equal expressions without changing the truth value. That is, given `h1 : a = b` and `h2 : p a`, we can construct a proof for `p b` using substitution: `Eq.subst h1 h2`. Example: ``` example (α : Type) (a b : α) (p : α → Prop) (h1 : a = b) (h2 : p a) : p b := Eq.subst h1 h2 example (α : Type) (a b : α) (p : α → Prop) (h1 : a = b) (h2 : p a) : p b := h1 ▸ h2 ``` The triangle in the second presentation is a macro built on top of `Eq.subst` and `Eq.symm`, and you can enter it by typing `\t`. For more information: [Equality](https://lean-lang.org/theorem_proving_in_lean4/quantifiers_and_equality.html#equality) 2 * HMul.hMul.{u, v, w} {α : Type u} {β : Type v} {γ : outParam (Type w)} [self : HMul α β γ] (a✝ : α) (a✝¹ : β) : γ`a * b` computes the product of `a` and `b`. The meaning of this notation is type-dependent. halfNat)Or (a b : Prop) : Prop`Or a b`, or `a ∨ b`, is the disjunction of propositions. There are two constructors for `Or`, called `Or.inl : a → a ∨ b` and `Or.inr : b → a ∨ b`, and you can use `match` or `cases` to destruct an `Or` assumption into the two cases. ∃ half, Nat.succNat.succ (n : Nat) : NatThe successor function on natural numbers, `succ n = n + 1`. This is one of the two constructors of `Nat`. n'Nat = Eq.{u_1} {α : Sort u_1} (a✝a✝¹ : α) : PropThe equality relation. It has one introduction rule, `Eq.refl`. We use `a = b` as notation for `Eq a b`. A fundamental property of equality is that it is an equivalence relation. ``` variable (α : Type) (a b c d : α) variable (hab : a = b) (hcb : c = b) (hcd : c = d) example : a = d := Eq.trans (Eq.trans hab (Eq.symm hcb)) hcd ``` Equality is much more than an equivalence relation, however. It has the important property that every assertion respects the equivalence, in the sense that we can substitute equal expressions without changing the truth value. That is, given `h1 : a = b` and `h2 : p a`, we can construct a proof for `p b` using substitution: `Eq.subst h1 h2`. Example: ``` example (α : Type) (a b : α) (p : α → Prop) (h1 : a = b) (h2 : p a) : p b := Eq.subst h1 h2 example (α : Type) (a b : α) (p : α → Prop) (h1 : a = b) (h2 : p a) : p b := h1 ▸ h2 ``` The triangle in the second presentation is a macro built on top of `Eq.subst` and `Eq.symm`, and you can enter it by typing `\t`. For more information: [Equality](https://lean-lang.org/theorem_proving_in_lean4/quantifiers_and_equality.html#equality) 2 * HMul.hMul.{u, v, w} {α : Type u} {β : Type v} {γ : outParam (Type w)} [self : HMul α β γ] (a✝ : α) (a✝¹ : β) : γ`a * b` computes the product of `a` and `b`. The meaning of this notation is type-dependent. halfNat + HAdd.hAdd.{u, v, w} {α : Type u} {β : Type v} {γ : outParam (Type w)} [self : HAdd α β γ] (a✝ : α) (a✝¹ : β) : γ`a + b` computes the sum of `a` and `b`. The meaning of this notation is type-dependent. 1
succ.inl.intro
n'Nat:NatNat : TypeThe type of natural numbers, starting at zero. It is defined as an inductive type freely generated by "zero is a natural number" and "the successor of a natural number is a natural number". You can prove a theorem `P n` about `n : Nat` by `induction n`, which will expect a proof of the theorem for `P 0`, and a proof of `P (succ i)` assuming a proof of `P i`. The same method also works to define functions by recursion on natural numbers: induction and recursion are two expressions of the same operation from Lean's point of view. ``` open Nat example (n : Nat) : n < succ n := by induction n with | zero => show 0 < 1 decide | succ i ih => -- ih : i < succ i show succ i < succ (succ i) exact Nat.succ_lt_succ ih ``` This type is special-cased by both the kernel and the compiler: * The type of expressions contains "`Nat` literals" as a primitive constructor, and the kernel knows how to reduce zero/succ expressions to nat literals. * If implemented naively, this type would represent a numeral `n` in unary as a linked list with `n` links, which is horribly inefficient. Instead, the runtime itself has a special representation for `Nat` which stores numbers up to 2^63 directly and larger numbers use an arbitrary precision "bignum" library (usually [GMP](https://gmplib.org/)).
halfNat:NatNat : TypeThe type of natural numbers, starting at zero. It is defined as an inductive type freely generated by "zero is a natural number" and "the successor of a natural number is a natural number". You can prove a theorem `P n` about `n : Nat` by `induction n`, which will expect a proof of the theorem for `P 0`, and a proof of `P (succ i)` assuming a proof of `P i`. The same method also works to define functions by recursion on natural numbers: induction and recursion are two expressions of the same operation from Lean's point of view. ``` open Nat example (n : Nat) : n < succ n := by induction n with | zero => show 0 < 1 decide | succ i ih => -- ih : i < succ i show succ i < succ (succ i) exact Nat.succ_lt_succ ih ``` This type is special-cased by both the kernel and the compiler: * The type of expressions contains "`Nat` literals" as a primitive constructor, and the kernel knows how to reduce zero/succ expressions to nat literals. * If implemented naively, this type would represent a numeral `n` in unary as a linked list with `n` links, which is horribly inefficient. Instead, the runtime itself has a special representation for `Nat` which stores numbers up to 2^63 directly and larger numbers use an arbitrary precision "bignum" library (usually [GMP](https://gmplib.org/)).
prfn' = 2 * half:n'Nat = Eq.{u_1} {α : Sort u_1} (a✝a✝¹ : α) : PropThe equality relation. It has one introduction rule, `Eq.refl`. We use `a = b` as notation for `Eq a b`. A fundamental property of equality is that it is an equivalence relation. ``` variable (α : Type) (a b c d : α) variable (hab : a = b) (hcb : c = b) (hcd : c = d) example : a = d := Eq.trans (Eq.trans hab (Eq.symm hcb)) hcd ``` Equality is much more than an equivalence relation, however. It has the important property that every assertion respects the equivalence, in the sense that we can substitute equal expressions without changing the truth value. That is, given `h1 : a = b` and `h2 : p a`, we can construct a proof for `p b` using substitution: `Eq.subst h1 h2`. Example: ``` example (α : Type) (a b : α) (p : α → Prop) (h1 : a = b) (h2 : p a) : p b := Eq.subst h1 h2 example (α : Type) (a b : α) (p : α → Prop) (h1 : a = b) (h2 : p a) : p b := h1 ▸ h2 ``` The triangle in the second presentation is a macro built on top of `Eq.subst` and `Eq.symm`, and you can enter it by typing `\t`. For more information: [Equality](https://lean-lang.org/theorem_proving_in_lean4/quantifiers_and_equality.html#equality) 2 * HMul.hMul.{u, v, w} {α : Type u} {β : Type v} {γ : outParam (Type w)} [self : HMul α β γ] (a✝ : α) (a✝¹ : β) : γ`a * b` computes the product of `a` and `b`. The meaning of this notation is type-dependent. halfNat
(∃ half, Nat.succNat.succ (n : Nat) : NatThe successor function on natural numbers, `succ n = n + 1`. This is one of the two constructors of `Nat`. n'Nat = Eq.{u_1} {α : Sort u_1} (a✝a✝¹ : α) : PropThe equality relation. It has one introduction rule, `Eq.refl`. We use `a = b` as notation for `Eq a b`. A fundamental property of equality is that it is an equivalence relation. ``` variable (α : Type) (a b c d : α) variable (hab : a = b) (hcb : c = b) (hcd : c = d) example : a = d := Eq.trans (Eq.trans hab (Eq.symm hcb)) hcd ``` Equality is much more than an equivalence relation, however. It has the important property that every assertion respects the equivalence, in the sense that we can substitute equal expressions without changing the truth value. That is, given `h1 : a = b` and `h2 : p a`, we can construct a proof for `p b` using substitution: `Eq.subst h1 h2`. Example: ``` example (α : Type) (a b : α) (p : α → Prop) (h1 : a = b) (h2 : p a) : p b := Eq.subst h1 h2 example (α : Type) (a b : α) (p : α → Prop) (h1 : a = b) (h2 : p a) : p b := h1 ▸ h2 ``` The triangle in the second presentation is a macro built on top of `Eq.subst` and `Eq.symm`, and you can enter it by typing `\t`. For more information: [Equality](https://lean-lang.org/theorem_proving_in_lean4/quantifiers_and_equality.html#equality) 2 * HMul.hMul.{u, v, w} {α : Type u} {β : Type v} {γ : outParam (Type w)} [self : HMul α β γ] (a✝ : α) (a✝¹ : β) : γ`a * b` computes the product of `a` and `b`. The meaning of this notation is type-dependent. halfNat)Or (a b : Prop) : Prop`Or a b`, or `a ∨ b`, is the disjunction of propositions. There are two constructors for `Or`, called `Or.inl : a → a ∨ b` and `Or.inr : b → a ∨ b`, and you can use `match` or `cases` to destruct an `Or` assumption into the two cases. ∃ half, Nat.succNat.succ (n : Nat) : NatThe successor function on natural numbers, `succ n = n + 1`. This is one of the two constructors of `Nat`. n'Nat = Eq.{u_1} {α : Sort u_1} (a✝a✝¹ : α) : PropThe equality relation. It has one introduction rule, `Eq.refl`. We use `a = b` as notation for `Eq a b`. A fundamental property of equality is that it is an equivalence relation. ``` variable (α : Type) (a b c d : α) variable (hab : a = b) (hcb : c = b) (hcd : c = d) example : a = d := Eq.trans (Eq.trans hab (Eq.symm hcb)) hcd ``` Equality is much more than an equivalence relation, however. It has the important property that every assertion respects the equivalence, in the sense that we can substitute equal expressions without changing the truth value. That is, given `h1 : a = b` and `h2 : p a`, we can construct a proof for `p b` using substitution: `Eq.subst h1 h2`. Example: ``` example (α : Type) (a b : α) (p : α → Prop) (h1 : a = b) (h2 : p a) : p b := Eq.subst h1 h2 example (α : Type) (a b : α) (p : α → Prop) (h1 : a = b) (h2 : p a) : p b := h1 ▸ h2 ``` The triangle in the second presentation is a macro built on top of `Eq.subst` and `Eq.symm`, and you can enter it by typing `\t`. For more information: [Equality](https://lean-lang.org/theorem_proving_in_lean4/quantifiers_and_equality.html#equality) 2 * HMul.hMul.{u, v, w} {α : Type u} {β : Type v} {γ : outParam (Type w)} [self : HMul α β γ] (a✝ : α) (a✝¹ : β) : γ`a * b` computes the product of `a` and `b`. The meaning of this notation is type-dependent. halfNat + HAdd.hAdd.{u, v, w} {α : Type u} {β : Type v} {γ : outParam (Type w)} [self : HAdd α β γ] (a✝ : α) (a✝¹ : β) : γ`a + b` computes the sum of `a` and `b`. The meaning of this notation is type-dependent. 1
succ.inr.intro
n'Nat:NatNat : TypeThe type of natural numbers, starting at zero. It is defined as an inductive type freely generated by "zero is a natural number" and "the successor of a natural number is a natural number". You can prove a theorem `P n` about `n : Nat` by `induction n`, which will expect a proof of the theorem for `P 0`, and a proof of `P (succ i)` assuming a proof of `P i`. The same method also works to define functions by recursion on natural numbers: induction and recursion are two expressions of the same operation from Lean's point of view. ``` open Nat example (n : Nat) : n < succ n := by induction n with | zero => show 0 < 1 decide | succ i ih => -- ih : i < succ i show succ i < succ (succ i) exact Nat.succ_lt_succ ih ``` This type is special-cased by both the kernel and the compiler: * The type of expressions contains "`Nat` literals" as a primitive constructor, and the kernel knows how to reduce zero/succ expressions to nat literals. * If implemented naively, this type would represent a numeral `n` in unary as a linked list with `n` links, which is horribly inefficient. Instead, the runtime itself has a special representation for `Nat` which stores numbers up to 2^63 directly and larger numbers use an arbitrary precision "bignum" library (usually [GMP](https://gmplib.org/)).
halfNat:NatNat : TypeThe type of natural numbers, starting at zero. It is defined as an inductive type freely generated by "zero is a natural number" and "the successor of a natural number is a natural number". You can prove a theorem `P n` about `n : Nat` by `induction n`, which will expect a proof of the theorem for `P 0`, and a proof of `P (succ i)` assuming a proof of `P i`. The same method also works to define functions by recursion on natural numbers: induction and recursion are two expressions of the same operation from Lean's point of view. ``` open Nat example (n : Nat) : n < succ n := by induction n with | zero => show 0 < 1 decide | succ i ih => -- ih : i < succ i show succ i < succ (succ i) exact Nat.succ_lt_succ ih ``` This type is special-cased by both the kernel and the compiler: * The type of expressions contains "`Nat` literals" as a primitive constructor, and the kernel knows how to reduce zero/succ expressions to nat literals. * If implemented naively, this type would represent a numeral `n` in unary as a linked list with `n` links, which is horribly inefficient. Instead, the runtime itself has a special representation for `Nat` which stores numbers up to 2^63 directly and larger numbers use an arbitrary precision "bignum" library (usually [GMP](https://gmplib.org/)).
prfn' = 2 * half + 1:n'Nat = Eq.{u_1} {α : Sort u_1} (a✝a✝¹ : α) : PropThe equality relation. It has one introduction rule, `Eq.refl`. We use `a = b` as notation for `Eq a b`. A fundamental property of equality is that it is an equivalence relation. ``` variable (α : Type) (a b c d : α) variable (hab : a = b) (hcb : c = b) (hcd : c = d) example : a = d := Eq.trans (Eq.trans hab (Eq.symm hcb)) hcd ``` Equality is much more than an equivalence relation, however. It has the important property that every assertion respects the equivalence, in the sense that we can substitute equal expressions without changing the truth value. That is, given `h1 : a = b` and `h2 : p a`, we can construct a proof for `p b` using substitution: `Eq.subst h1 h2`. Example: ``` example (α : Type) (a b : α) (p : α → Prop) (h1 : a = b) (h2 : p a) : p b := Eq.subst h1 h2 example (α : Type) (a b : α) (p : α → Prop) (h1 : a = b) (h2 : p a) : p b := h1 ▸ h2 ``` The triangle in the second presentation is a macro built on top of `Eq.subst` and `Eq.symm`, and you can enter it by typing `\t`. For more information: [Equality](https://lean-lang.org/theorem_proving_in_lean4/quantifiers_and_equality.html#equality) 2 * HMul.hMul.{u, v, w} {α : Type u} {β : Type v} {γ : outParam (Type w)} [self : HMul α β γ] (a✝ : α) (a✝¹ : β) : γ`a * b` computes the product of `a` and `b`. The meaning of this notation is type-dependent. halfNat + HAdd.hAdd.{u, v, w} {α : Type u} {β : Type v} {γ : outParam (Type w)} [self : HAdd α β γ] (a✝ : α) (a✝¹ : β) : γ`a + b` computes the sum of `a` and `b`. The meaning of this notation is type-dependent. 1
(∃ half, Nat.succNat.succ (n : Nat) : NatThe successor function on natural numbers, `succ n = n + 1`. This is one of the two constructors of `Nat`. n'Nat = Eq.{u_1} {α : Sort u_1} (a✝a✝¹ : α) : PropThe equality relation. It has one introduction rule, `Eq.refl`. We use `a = b` as notation for `Eq a b`. A fundamental property of equality is that it is an equivalence relation. ``` variable (α : Type) (a b c d : α) variable (hab : a = b) (hcb : c = b) (hcd : c = d) example : a = d := Eq.trans (Eq.trans hab (Eq.symm hcb)) hcd ``` Equality is much more than an equivalence relation, however. It has the important property that every assertion respects the equivalence, in the sense that we can substitute equal expressions without changing the truth value. That is, given `h1 : a = b` and `h2 : p a`, we can construct a proof for `p b` using substitution: `Eq.subst h1 h2`. Example: ``` example (α : Type) (a b : α) (p : α → Prop) (h1 : a = b) (h2 : p a) : p b := Eq.subst h1 h2 example (α : Type) (a b : α) (p : α → Prop) (h1 : a = b) (h2 : p a) : p b := h1 ▸ h2 ``` The triangle in the second presentation is a macro built on top of `Eq.subst` and `Eq.symm`, and you can enter it by typing `\t`. For more information: [Equality](https://lean-lang.org/theorem_proving_in_lean4/quantifiers_and_equality.html#equality) 2 * HMul.hMul.{u, v, w} {α : Type u} {β : Type v} {γ : outParam (Type w)} [self : HMul α β γ] (a✝ : α) (a✝¹ : β) : γ`a * b` computes the product of `a` and `b`. The meaning of this notation is type-dependent. halfNat)Or (a b : Prop) : Prop`Or a b`, or `a ∨ b`, is the disjunction of propositions. There are two constructors for `Or`, called `Or.inl : a → a ∨ b` and `Or.inr : b → a ∨ b`, and you can use `match` or `cases` to destruct an `Or` assumption into the two cases. ∃ half, Nat.succNat.succ (n : Nat) : NatThe successor function on natural numbers, `succ n = n + 1`. This is one of the two constructors of `Nat`. n'Nat = Eq.{u_1} {α : Sort u_1} (a✝a✝¹ : α) : PropThe equality relation. It has one introduction rule, `Eq.refl`. We use `a = b` as notation for `Eq a b`. A fundamental property of equality is that it is an equivalence relation. ``` variable (α : Type) (a b c d : α) variable (hab : a = b) (hcb : c = b) (hcd : c = d) example : a = d := Eq.trans (Eq.trans hab (Eq.symm hcb)) hcd ``` Equality is much more than an equivalence relation, however. It has the important property that every assertion respects the equivalence, in the sense that we can substitute equal expressions without changing the truth value. That is, given `h1 : a = b` and `h2 : p a`, we can construct a proof for `p b` using substitution: `Eq.subst h1 h2`. Example: ``` example (α : Type) (a b : α) (p : α → Prop) (h1 : a = b) (h2 : p a) : p b := Eq.subst h1 h2 example (α : Type) (a b : α) (p : α → Prop) (h1 : a = b) (h2 : p a) : p b := h1 ▸ h2 ``` The triangle in the second presentation is a macro built on top of `Eq.subst` and `Eq.symm`, and you can enter it by typing `\t`. For more information: [Equality](https://lean-lang.org/theorem_proving_in_lean4/quantifiers_and_equality.html#equality) 2 * HMul.hMul.{u, v, w} {α : Type u} {β : Type v} {γ : outParam (Type w)} [self : HMul α β γ] (a✝ : α) (a✝¹ : β) : γ`a * b` computes the product of `a` and `b`. The meaning of this notation is type-dependent. halfNat + HAdd.hAdd.{u, v, w} {α : Type u} {β : Type v} {γ : outParam (Type w)} [self : HAdd α β γ] (a✝ : α) (a✝¹ : β) : γ`a + b` computes the sum of `a` and `b`. The meaning of this notation is type-dependent. 1
succ.inl.intro
n'Nat:NatNat : TypeThe type of natural numbers, starting at zero. It is defined as an inductive type freely generated by "zero is a natural number" and "the successor of a natural number is a natural number". You can prove a theorem `P n` about `n : Nat` by `induction n`, which will expect a proof of the theorem for `P 0`, and a proof of `P (succ i)` assuming a proof of `P i`. The same method also works to define functions by recursion on natural numbers: induction and recursion are two expressions of the same operation from Lean's point of view. ``` open Nat example (n : Nat) : n < succ n := by induction n with | zero => show 0 < 1 decide | succ i ih => -- ih : i < succ i show succ i < succ (succ i) exact Nat.succ_lt_succ ih ``` This type is special-cased by both the kernel and the compiler: * The type of expressions contains "`Nat` literals" as a primitive constructor, and the kernel knows how to reduce zero/succ expressions to nat literals. * If implemented naively, this type would represent a numeral `n` in unary as a linked list with `n` links, which is horribly inefficient. Instead, the runtime itself has a special representation for `Nat` which stores numbers up to 2^63 directly and larger numbers use an arbitrary precision "bignum" library (usually [GMP](https://gmplib.org/)).
halfNat:NatNat : TypeThe type of natural numbers, starting at zero. It is defined as an inductive type freely generated by "zero is a natural number" and "the successor of a natural number is a natural number". You can prove a theorem `P n` about `n : Nat` by `induction n`, which will expect a proof of the theorem for `P 0`, and a proof of `P (succ i)` assuming a proof of `P i`. The same method also works to define functions by recursion on natural numbers: induction and recursion are two expressions of the same operation from Lean's point of view. ``` open Nat example (n : Nat) : n < succ n := by induction n with | zero => show 0 < 1 decide | succ i ih => -- ih : i < succ i show succ i < succ (succ i) exact Nat.succ_lt_succ ih ``` This type is special-cased by both the kernel and the compiler: * The type of expressions contains "`Nat` literals" as a primitive constructor, and the kernel knows how to reduce zero/succ expressions to nat literals. * If implemented naively, this type would represent a numeral `n` in unary as a linked list with `n` links, which is horribly inefficient. Instead, the runtime itself has a special representation for `Nat` which stores numbers up to 2^63 directly and larger numbers use an arbitrary precision "bignum" library (usually [GMP](https://gmplib.org/)).
prfn' = 2 * half:n'Nat = Eq.{u_1} {α : Sort u_1} (a✝a✝¹ : α) : PropThe equality relation. It has one introduction rule, `Eq.refl`. We use `a = b` as notation for `Eq a b`. A fundamental property of equality is that it is an equivalence relation. ``` variable (α : Type) (a b c d : α) variable (hab : a = b) (hcb : c = b) (hcd : c = d) example : a = d := Eq.trans (Eq.trans hab (Eq.symm hcb)) hcd ``` Equality is much more than an equivalence relation, however. It has the important property that every assertion respects the equivalence, in the sense that we can substitute equal expressions without changing the truth value. That is, given `h1 : a = b` and `h2 : p a`, we can construct a proof for `p b` using substitution: `Eq.subst h1 h2`. Example: ``` example (α : Type) (a b : α) (p : α → Prop) (h1 : a = b) (h2 : p a) : p b := Eq.subst h1 h2 example (α : Type) (a b : α) (p : α → Prop) (h1 : a = b) (h2 : p a) : p b := h1 ▸ h2 ``` The triangle in the second presentation is a macro built on top of `Eq.subst` and `Eq.symm`, and you can enter it by typing `\t`. For more information: [Equality](https://lean-lang.org/theorem_proving_in_lean4/quantifiers_and_equality.html#equality) 2 * HMul.hMul.{u, v, w} {α : Type u} {β : Type v} {γ : outParam (Type w)} [self : HMul α β γ] (a✝ : α) (a✝¹ : β) : γ`a * b` computes the product of `a` and `b`. The meaning of this notation is type-dependent. halfNat
(∃ half, Nat.succNat.succ (n : Nat) : NatThe successor function on natural numbers, `succ n = n + 1`. This is one of the two constructors of `Nat`. n'Nat = Eq.{u_1} {α : Sort u_1} (a✝a✝¹ : α) : PropThe equality relation. It has one introduction rule, `Eq.refl`. We use `a = b` as notation for `Eq a b`. A fundamental property of equality is that it is an equivalence relation. ``` variable (α : Type) (a b c d : α) variable (hab : a = b) (hcb : c = b) (hcd : c = d) example : a = d := Eq.trans (Eq.trans hab (Eq.symm hcb)) hcd ``` Equality is much more than an equivalence relation, however. It has the important property that every assertion respects the equivalence, in the sense that we can substitute equal expressions without changing the truth value. That is, given `h1 : a = b` and `h2 : p a`, we can construct a proof for `p b` using substitution: `Eq.subst h1 h2`. Example: ``` example (α : Type) (a b : α) (p : α → Prop) (h1 : a = b) (h2 : p a) : p b := Eq.subst h1 h2 example (α : Type) (a b : α) (p : α → Prop) (h1 : a = b) (h2 : p a) : p b := h1 ▸ h2 ``` The triangle in the second presentation is a macro built on top of `Eq.subst` and `Eq.symm`, and you can enter it by typing `\t`. For more information: [Equality](https://lean-lang.org/theorem_proving_in_lean4/quantifiers_and_equality.html#equality) 2 * HMul.hMul.{u, v, w} {α : Type u} {β : Type v} {γ : outParam (Type w)} [self : HMul α β γ] (a✝ : α) (a✝¹ : β) : γ`a * b` computes the product of `a` and `b`. The meaning of this notation is type-dependent. halfNat)Or (a b : Prop) : Prop`Or a b`, or `a ∨ b`, is the disjunction of propositions. There are two constructors for `Or`, called `Or.inl : a → a ∨ b` and `Or.inr : b → a ∨ b`, and you can use `match` or `cases` to destruct an `Or` assumption into the two cases. ∃ half, Nat.succNat.succ (n : Nat) : NatThe successor function on natural numbers, `succ n = n + 1`. This is one of the two constructors of `Nat`. n'Nat = Eq.{u_1} {α : Sort u_1} (a✝a✝¹ : α) : PropThe equality relation. It has one introduction rule, `Eq.refl`. We use `a = b` as notation for `Eq a b`. A fundamental property of equality is that it is an equivalence relation. ``` variable (α : Type) (a b c d : α) variable (hab : a = b) (hcb : c = b) (hcd : c = d) example : a = d := Eq.trans (Eq.trans hab (Eq.symm hcb)) hcd ``` Equality is much more than an equivalence relation, however. It has the important property that every assertion respects the equivalence, in the sense that we can substitute equal expressions without changing the truth value. That is, given `h1 : a = b` and `h2 : p a`, we can construct a proof for `p b` using substitution: `Eq.subst h1 h2`. Example: ``` example (α : Type) (a b : α) (p : α → Prop) (h1 : a = b) (h2 : p a) : p b := Eq.subst h1 h2 example (α : Type) (a b : α) (p : α → Prop) (h1 : a = b) (h2 : p a) : p b := h1 ▸ h2 ``` The triangle in the second presentation is a macro built on top of `Eq.subst` and `Eq.symm`, and you can enter it by typing `\t`. For more information: [Equality](https://lean-lang.org/theorem_proving_in_lean4/quantifiers_and_equality.html#equality) 2 * HMul.hMul.{u, v, w} {α : Type u} {β : Type v} {γ : outParam (Type w)} [self : HMul α β γ] (a✝ : α) (a✝¹ : β) : γ`a * b` computes the product of `a` and `b`. The meaning of this notation is type-dependent. halfNat + HAdd.hAdd.{u, v, w} {α : Type u} {β : Type v} {γ : outParam (Type w)} [self : HAdd α β γ] (a✝ : α) (a✝¹ : β) : γ`a + b` computes the sum of `a` and `b`. The meaning of this notation is type-dependent. 1
succ.inl.intro.h
n'Nat:NatNat : TypeThe type of natural numbers, starting at zero. It is defined as an inductive type freely generated by "zero is a natural number" and "the successor of a natural number is a natural number". You can prove a theorem `P n` about `n : Nat` by `induction n`, which will expect a proof of the theorem for `P 0`, and a proof of `P (succ i)` assuming a proof of `P i`. The same method also works to define functions by recursion on natural numbers: induction and recursion are two expressions of the same operation from Lean's point of view. ``` open Nat example (n : Nat) : n < succ n := by induction n with | zero => show 0 < 1 decide | succ i ih => -- ih : i < succ i show succ i < succ (succ i) exact Nat.succ_lt_succ ih ``` This type is special-cased by both the kernel and the compiler: * The type of expressions contains "`Nat` literals" as a primitive constructor, and the kernel knows how to reduce zero/succ expressions to nat literals. * If implemented naively, this type would represent a numeral `n` in unary as a linked list with `n` links, which is horribly inefficient. Instead, the runtime itself has a special representation for `Nat` which stores numbers up to 2^63 directly and larger numbers use an arbitrary precision "bignum" library (usually [GMP](https://gmplib.org/)).
halfNat:NatNat : TypeThe type of natural numbers, starting at zero. It is defined as an inductive type freely generated by "zero is a natural number" and "the successor of a natural number is a natural number". You can prove a theorem `P n` about `n : Nat` by `induction n`, which will expect a proof of the theorem for `P 0`, and a proof of `P (succ i)` assuming a proof of `P i`. The same method also works to define functions by recursion on natural numbers: induction and recursion are two expressions of the same operation from Lean's point of view. ``` open Nat example (n : Nat) : n < succ n := by induction n with | zero => show 0 < 1 decide | succ i ih => -- ih : i < succ i show succ i < succ (succ i) exact Nat.succ_lt_succ ih ``` This type is special-cased by both the kernel and the compiler: * The type of expressions contains "`Nat` literals" as a primitive constructor, and the kernel knows how to reduce zero/succ expressions to nat literals. * If implemented naively, this type would represent a numeral `n` in unary as a linked list with `n` links, which is horribly inefficient. Instead, the runtime itself has a special representation for `Nat` which stores numbers up to 2^63 directly and larger numbers use an arbitrary precision "bignum" library (usually [GMP](https://gmplib.org/)).
prfn' = 2 * half:n'Nat = Eq.{u_1} {α : Sort u_1} (a✝a✝¹ : α) : PropThe equality relation. It has one introduction rule, `Eq.refl`. We use `a = b` as notation for `Eq a b`. A fundamental property of equality is that it is an equivalence relation. ``` variable (α : Type) (a b c d : α) variable (hab : a = b) (hcb : c = b) (hcd : c = d) example : a = d := Eq.trans (Eq.trans hab (Eq.symm hcb)) hcd ``` Equality is much more than an equivalence relation, however. It has the important property that every assertion respects the equivalence, in the sense that we can substitute equal expressions without changing the truth value. That is, given `h1 : a = b` and `h2 : p a`, we can construct a proof for `p b` using substitution: `Eq.subst h1 h2`. Example: ``` example (α : Type) (a b : α) (p : α → Prop) (h1 : a = b) (h2 : p a) : p b := Eq.subst h1 h2 example (α : Type) (a b : α) (p : α → Prop) (h1 : a = b) (h2 : p a) : p b := h1 ▸ h2 ``` The triangle in the second presentation is a macro built on top of `Eq.subst` and `Eq.symm`, and you can enter it by typing `\t`. For more information: [Equality](https://lean-lang.org/theorem_proving_in_lean4/quantifiers_and_equality.html#equality) 2 * HMul.hMul.{u, v, w} {α : Type u} {β : Type v} {γ : outParam (Type w)} [self : HMul α β γ] (a✝ : α) (a✝¹ : β) : γ`a * b` computes the product of `a` and `b`. The meaning of this notation is type-dependent. halfNat
∃ half, Nat.succNat.succ (n : Nat) : NatThe successor function on natural numbers, `succ n = n + 1`. This is one of the two constructors of `Nat`. n'Nat = Eq.{u_1} {α : Sort u_1} (a✝a✝¹ : α) : PropThe equality relation. It has one introduction rule, `Eq.refl`. We use `a = b` as notation for `Eq a b`. A fundamental property of equality is that it is an equivalence relation. ``` variable (α : Type) (a b c d : α) variable (hab : a = b) (hcb : c = b) (hcd : c = d) example : a = d := Eq.trans (Eq.trans hab (Eq.symm hcb)) hcd ``` Equality is much more than an equivalence relation, however. It has the important property that every assertion respects the equivalence, in the sense that we can substitute equal expressions without changing the truth value. That is, given `h1 : a = b` and `h2 : p a`, we can construct a proof for `p b` using substitution: `Eq.subst h1 h2`. Example: ``` example (α : Type) (a b : α) (p : α → Prop) (h1 : a = b) (h2 : p a) : p b := Eq.subst h1 h2 example (α : Type) (a b : α) (p : α → Prop) (h1 : a = b) (h2 : p a) : p b := h1 ▸ h2 ``` The triangle in the second presentation is a macro built on top of `Eq.subst` and `Eq.symm`, and you can enter it by typing `\t`. For more information: [Equality](https://lean-lang.org/theorem_proving_in_lean4/quantifiers_and_equality.html#equality) 2 * HMul.hMul.{u, v, w} {α : Type u} {β : Type v} {γ : outParam (Type w)} [self : HMul α β γ] (a✝ : α) (a✝¹ : β) : γ`a * b` computes the product of `a` and `b`. The meaning of this notation is type-dependent. halfNat + HAdd.hAdd.{u, v, w} {α : Type u} {β : Type v} {γ : outParam (Type w)} [self : HAdd α β γ] (a✝ : α) (a✝¹ : β) : γ`a + b` computes the sum of `a` and `b`. The meaning of this notation is type-dependent. 1
succ.inl.intro.h
n'Nat:NatNat : TypeThe type of natural numbers, starting at zero. It is defined as an inductive type freely generated by "zero is a natural number" and "the successor of a natural number is a natural number". You can prove a theorem `P n` about `n : Nat` by `induction n`, which will expect a proof of the theorem for `P 0`, and a proof of `P (succ i)` assuming a proof of `P i`. The same method also works to define functions by recursion on natural numbers: induction and recursion are two expressions of the same operation from Lean's point of view. ``` open Nat example (n : Nat) : n < succ n := by induction n with | zero => show 0 < 1 decide | succ i ih => -- ih : i < succ i show succ i < succ (succ i) exact Nat.succ_lt_succ ih ``` This type is special-cased by both the kernel and the compiler: * The type of expressions contains "`Nat` literals" as a primitive constructor, and the kernel knows how to reduce zero/succ expressions to nat literals. * If implemented naively, this type would represent a numeral `n` in unary as a linked list with `n` links, which is horribly inefficient. Instead, the runtime itself has a special representation for `Nat` which stores numbers up to 2^63 directly and larger numbers use an arbitrary precision "bignum" library (usually [GMP](https://gmplib.org/)).
halfNat:NatNat : TypeThe type of natural numbers, starting at zero. It is defined as an inductive type freely generated by "zero is a natural number" and "the successor of a natural number is a natural number". You can prove a theorem `P n` about `n : Nat` by `induction n`, which will expect a proof of the theorem for `P 0`, and a proof of `P (succ i)` assuming a proof of `P i`. The same method also works to define functions by recursion on natural numbers: induction and recursion are two expressions of the same operation from Lean's point of view. ``` open Nat example (n : Nat) : n < succ n := by induction n with | zero => show 0 < 1 decide | succ i ih => -- ih : i < succ i show succ i < succ (succ i) exact Nat.succ_lt_succ ih ``` This type is special-cased by both the kernel and the compiler: * The type of expressions contains "`Nat` literals" as a primitive constructor, and the kernel knows how to reduce zero/succ expressions to nat literals. * If implemented naively, this type would represent a numeral `n` in unary as a linked list with `n` links, which is horribly inefficient. Instead, the runtime itself has a special representation for `Nat` which stores numbers up to 2^63 directly and larger numbers use an arbitrary precision "bignum" library (usually [GMP](https://gmplib.org/)).
prfn' = 2 * half:n'Nat = Eq.{u_1} {α : Sort u_1} (a✝a✝¹ : α) : PropThe equality relation. It has one introduction rule, `Eq.refl`. We use `a = b` as notation for `Eq a b`. A fundamental property of equality is that it is an equivalence relation. ``` variable (α : Type) (a b c d : α) variable (hab : a = b) (hcb : c = b) (hcd : c = d) example : a = d := Eq.trans (Eq.trans hab (Eq.symm hcb)) hcd ``` Equality is much more than an equivalence relation, however. It has the important property that every assertion respects the equivalence, in the sense that we can substitute equal expressions without changing the truth value. That is, given `h1 : a = b` and `h2 : p a`, we can construct a proof for `p b` using substitution: `Eq.subst h1 h2`. Example: ``` example (α : Type) (a b : α) (p : α → Prop) (h1 : a = b) (h2 : p a) : p b := Eq.subst h1 h2 example (α : Type) (a b : α) (p : α → Prop) (h1 : a = b) (h2 : p a) : p b := h1 ▸ h2 ``` The triangle in the second presentation is a macro built on top of `Eq.subst` and `Eq.symm`, and you can enter it by typing `\t`. For more information: [Equality](https://lean-lang.org/theorem_proving_in_lean4/quantifiers_and_equality.html#equality) 2 * HMul.hMul.{u, v, w} {α : Type u} {β : Type v} {γ : outParam (Type w)} [self : HMul α β γ] (a✝ : α) (a✝¹ : β) : γ`a * b` computes the product of `a` and `b`. The meaning of this notation is type-dependent. halfNat
Nat.succNat.succ (n : Nat) : NatThe successor function on natural numbers, `succ n = n + 1`. This is one of the two constructors of `Nat`. n'Nat = Eq.{u_1} {α : Sort u_1} (a✝a✝¹ : α) : PropThe equality relation. It has one introduction rule, `Eq.refl`. We use `a = b` as notation for `Eq a b`. A fundamental property of equality is that it is an equivalence relation. ``` variable (α : Type) (a b c d : α) variable (hab : a = b) (hcb : c = b) (hcd : c = d) example : a = d := Eq.trans (Eq.trans hab (Eq.symm hcb)) hcd ``` Equality is much more than an equivalence relation, however. It has the important property that every assertion respects the equivalence, in the sense that we can substitute equal expressions without changing the truth value. That is, given `h1 : a = b` and `h2 : p a`, we can construct a proof for `p b` using substitution: `Eq.subst h1 h2`. Example: ``` example (α : Type) (a b : α) (p : α → Prop) (h1 : a = b) (h2 : p a) : p b := Eq.subst h1 h2 example (α : Type) (a b : α) (p : α → Prop) (h1 : a = b) (h2 : p a) : p b := h1 ▸ h2 ``` The triangle in the second presentation is a macro built on top of `Eq.subst` and `Eq.symm`, and you can enter it by typing `\t`. For more information: [Equality](https://lean-lang.org/theorem_proving_in_lean4/quantifiers_and_equality.html#equality) 2 * HMul.hMul.{u, v, w} {α : Type u} {β : Type v} {γ : outParam (Type w)} [self : HMul α β γ] (a✝ : α) (a✝¹ : β) : γ`a * b` computes the product of `a` and `b`. The meaning of this notation is type-dependent. halfNat + HAdd.hAdd.{u, v, w} {α : Type u} {β : Type v} {γ : outParam (Type w)} [self : HAdd α β γ] (a✝ : α) (a✝¹ : β) : γ`a + b` computes the sum of `a` and `b`. The meaning of this notation is type-dependent. 1
succ.inl.intro.h
n'Nat:NatNat : TypeThe type of natural numbers, starting at zero. It is defined as an inductive type freely generated by "zero is a natural number" and "the successor of a natural number is a natural number". You can prove a theorem `P n` about `n : Nat` by `induction n`, which will expect a proof of the theorem for `P 0`, and a proof of `P (succ i)` assuming a proof of `P i`. The same method also works to define functions by recursion on natural numbers: induction and recursion are two expressions of the same operation from Lean's point of view. ``` open Nat example (n : Nat) : n < succ n := by induction n with | zero => show 0 < 1 decide | succ i ih => -- ih : i < succ i show succ i < succ (succ i) exact Nat.succ_lt_succ ih ``` This type is special-cased by both the kernel and the compiler: * The type of expressions contains "`Nat` literals" as a primitive constructor, and the kernel knows how to reduce zero/succ expressions to nat literals. * If implemented naively, this type would represent a numeral `n` in unary as a linked list with `n` links, which is horribly inefficient. Instead, the runtime itself has a special representation for `Nat` which stores numbers up to 2^63 directly and larger numbers use an arbitrary precision "bignum" library (usually [GMP](https://gmplib.org/)).
halfNat:NatNat : TypeThe type of natural numbers, starting at zero. It is defined as an inductive type freely generated by "zero is a natural number" and "the successor of a natural number is a natural number". You can prove a theorem `P n` about `n : Nat` by `induction n`, which will expect a proof of the theorem for `P 0`, and a proof of `P (succ i)` assuming a proof of `P i`. The same method also works to define functions by recursion on natural numbers: induction and recursion are two expressions of the same operation from Lean's point of view. ``` open Nat example (n : Nat) : n < succ n := by induction n with | zero => show 0 < 1 decide | succ i ih => -- ih : i < succ i show succ i < succ (succ i) exact Nat.succ_lt_succ ih ``` This type is special-cased by both the kernel and the compiler: * The type of expressions contains "`Nat` literals" as a primitive constructor, and the kernel knows how to reduce zero/succ expressions to nat literals. * If implemented naively, this type would represent a numeral `n` in unary as a linked list with `n` links, which is horribly inefficient. Instead, the runtime itself has a special representation for `Nat` which stores numbers up to 2^63 directly and larger numbers use an arbitrary precision "bignum" library (usually [GMP](https://gmplib.org/)).
prfn' = 2 * half:n'Nat = Eq.{u_1} {α : Sort u_1} (a✝a✝¹ : α) : PropThe equality relation. It has one introduction rule, `Eq.refl`. We use `a = b` as notation for `Eq a b`. A fundamental property of equality is that it is an equivalence relation. ``` variable (α : Type) (a b c d : α) variable (hab : a = b) (hcb : c = b) (hcd : c = d) example : a = d := Eq.trans (Eq.trans hab (Eq.symm hcb)) hcd ``` Equality is much more than an equivalence relation, however. It has the important property that every assertion respects the equivalence, in the sense that we can substitute equal expressions without changing the truth value. That is, given `h1 : a = b` and `h2 : p a`, we can construct a proof for `p b` using substitution: `Eq.subst h1 h2`. Example: ``` example (α : Type) (a b : α) (p : α → Prop) (h1 : a = b) (h2 : p a) : p b := Eq.subst h1 h2 example (α : Type) (a b : α) (p : α → Prop) (h1 : a = b) (h2 : p a) : p b := h1 ▸ h2 ``` The triangle in the second presentation is a macro built on top of `Eq.subst` and `Eq.symm`, and you can enter it by typing `\t`. For more information: [Equality](https://lean-lang.org/theorem_proving_in_lean4/quantifiers_and_equality.html#equality) 2 * HMul.hMul.{u, v, w} {α : Type u} {β : Type v} {γ : outParam (Type w)} [self : HMul α β γ] (a✝ : α) (a✝¹ : β) : γ`a * b` computes the product of `a` and `b`. The meaning of this notation is type-dependent. halfNat
Nat.succNat.succ (n : Nat) : NatThe successor function on natural numbers, `succ n = n + 1`. This is one of the two constructors of `Nat`. n'Nat = Eq.{u_1} {α : Sort u_1} (a✝a✝¹ : α) : PropThe equality relation. It has one introduction rule, `Eq.refl`. We use `a = b` as notation for `Eq a b`. A fundamental property of equality is that it is an equivalence relation. ``` variable (α : Type) (a b c d : α) variable (hab : a = b) (hcb : c = b) (hcd : c = d) example : a = d := Eq.trans (Eq.trans hab (Eq.symm hcb)) hcd ``` Equality is much more than an equivalence relation, however. It has the important property that every assertion respects the equivalence, in the sense that we can substitute equal expressions without changing the truth value. That is, given `h1 : a = b` and `h2 : p a`, we can construct a proof for `p b` using substitution: `Eq.subst h1 h2`. Example: ``` example (α : Type) (a b : α) (p : α → Prop) (h1 : a = b) (h2 : p a) : p b := Eq.subst h1 h2 example (α : Type) (a b : α) (p : α → Prop) (h1 : a = b) (h2 : p a) : p b := h1 ▸ h2 ``` The triangle in the second presentation is a macro built on top of `Eq.subst` and `Eq.symm`, and you can enter it by typing `\t`. For more information: [Equality](https://lean-lang.org/theorem_proving_in_lean4/quantifiers_and_equality.html#equality) Nat.succNat.succ (n : Nat) : NatThe successor function on natural numbers, `succ n = n + 1`. This is one of the two constructors of `Nat`. (2 * HMul.hMul.{u, v, w} {α : Type u} {β : Type v} {γ : outParam (Type w)} [self : HMul α β γ] (a✝ : α) (a✝¹ : β) : γ`a * b` computes the product of `a` and `b`. The meaning of this notation is type-dependent. halfNat)
All goals completed! 🐙
succ.inr.intro
n'Nat:NatNat : TypeThe type of natural numbers, starting at zero. It is defined as an inductive type freely generated by "zero is a natural number" and "the successor of a natural number is a natural number". You can prove a theorem `P n` about `n : Nat` by `induction n`, which will expect a proof of the theorem for `P 0`, and a proof of `P (succ i)` assuming a proof of `P i`. The same method also works to define functions by recursion on natural numbers: induction and recursion are two expressions of the same operation from Lean's point of view. ``` open Nat example (n : Nat) : n < succ n := by induction n with | zero => show 0 < 1 decide | succ i ih => -- ih : i < succ i show succ i < succ (succ i) exact Nat.succ_lt_succ ih ``` This type is special-cased by both the kernel and the compiler: * The type of expressions contains "`Nat` literals" as a primitive constructor, and the kernel knows how to reduce zero/succ expressions to nat literals. * If implemented naively, this type would represent a numeral `n` in unary as a linked list with `n` links, which is horribly inefficient. Instead, the runtime itself has a special representation for `Nat` which stores numbers up to 2^63 directly and larger numbers use an arbitrary precision "bignum" library (usually [GMP](https://gmplib.org/)).
halfNat:NatNat : TypeThe type of natural numbers, starting at zero. It is defined as an inductive type freely generated by "zero is a natural number" and "the successor of a natural number is a natural number". You can prove a theorem `P n` about `n : Nat` by `induction n`, which will expect a proof of the theorem for `P 0`, and a proof of `P (succ i)` assuming a proof of `P i`. The same method also works to define functions by recursion on natural numbers: induction and recursion are two expressions of the same operation from Lean's point of view. ``` open Nat example (n : Nat) : n < succ n := by induction n with | zero => show 0 < 1 decide | succ i ih => -- ih : i < succ i show succ i < succ (succ i) exact Nat.succ_lt_succ ih ``` This type is special-cased by both the kernel and the compiler: * The type of expressions contains "`Nat` literals" as a primitive constructor, and the kernel knows how to reduce zero/succ expressions to nat literals. * If implemented naively, this type would represent a numeral `n` in unary as a linked list with `n` links, which is horribly inefficient. Instead, the runtime itself has a special representation for `Nat` which stores numbers up to 2^63 directly and larger numbers use an arbitrary precision "bignum" library (usually [GMP](https://gmplib.org/)).
prfn' = 2 * half + 1:n'Nat = Eq.{u_1} {α : Sort u_1} (a✝a✝¹ : α) : PropThe equality relation. It has one introduction rule, `Eq.refl`. We use `a = b` as notation for `Eq a b`. A fundamental property of equality is that it is an equivalence relation. ``` variable (α : Type) (a b c d : α) variable (hab : a = b) (hcb : c = b) (hcd : c = d) example : a = d := Eq.trans (Eq.trans hab (Eq.symm hcb)) hcd ``` Equality is much more than an equivalence relation, however. It has the important property that every assertion respects the equivalence, in the sense that we can substitute equal expressions without changing the truth value. That is, given `h1 : a = b` and `h2 : p a`, we can construct a proof for `p b` using substitution: `Eq.subst h1 h2`. Example: ``` example (α : Type) (a b : α) (p : α → Prop) (h1 : a = b) (h2 : p a) : p b := Eq.subst h1 h2 example (α : Type) (a b : α) (p : α → Prop) (h1 : a = b) (h2 : p a) : p b := h1 ▸ h2 ``` The triangle in the second presentation is a macro built on top of `Eq.subst` and `Eq.symm`, and you can enter it by typing `\t`. For more information: [Equality](https://lean-lang.org/theorem_proving_in_lean4/quantifiers_and_equality.html#equality) 2 * HMul.hMul.{u, v, w} {α : Type u} {β : Type v} {γ : outParam (Type w)} [self : HMul α β γ] (a✝ : α) (a✝¹ : β) : γ`a * b` computes the product of `a` and `b`. The meaning of this notation is type-dependent. halfNat + HAdd.hAdd.{u, v, w} {α : Type u} {β : Type v} {γ : outParam (Type w)} [self : HAdd α β γ] (a✝ : α) (a✝¹ : β) : γ`a + b` computes the sum of `a` and `b`. The meaning of this notation is type-dependent. 1
(∃ half, Nat.succNat.succ (n : Nat) : NatThe successor function on natural numbers, `succ n = n + 1`. This is one of the two constructors of `Nat`. n'Nat = Eq.{u_1} {α : Sort u_1} (a✝a✝¹ : α) : PropThe equality relation. It has one introduction rule, `Eq.refl`. We use `a = b` as notation for `Eq a b`. A fundamental property of equality is that it is an equivalence relation. ``` variable (α : Type) (a b c d : α) variable (hab : a = b) (hcb : c = b) (hcd : c = d) example : a = d := Eq.trans (Eq.trans hab (Eq.symm hcb)) hcd ``` Equality is much more than an equivalence relation, however. It has the important property that every assertion respects the equivalence, in the sense that we can substitute equal expressions without changing the truth value. That is, given `h1 : a = b` and `h2 : p a`, we can construct a proof for `p b` using substitution: `Eq.subst h1 h2`. Example: ``` example (α : Type) (a b : α) (p : α → Prop) (h1 : a = b) (h2 : p a) : p b := Eq.subst h1 h2 example (α : Type) (a b : α) (p : α → Prop) (h1 : a = b) (h2 : p a) : p b := h1 ▸ h2 ``` The triangle in the second presentation is a macro built on top of `Eq.subst` and `Eq.symm`, and you can enter it by typing `\t`. For more information: [Equality](https://lean-lang.org/theorem_proving_in_lean4/quantifiers_and_equality.html#equality) 2 * HMul.hMul.{u, v, w} {α : Type u} {β : Type v} {γ : outParam (Type w)} [self : HMul α β γ] (a✝ : α) (a✝¹ : β) : γ`a * b` computes the product of `a` and `b`. The meaning of this notation is type-dependent. halfNat)Or (a b : Prop) : Prop`Or a b`, or `a ∨ b`, is the disjunction of propositions. There are two constructors for `Or`, called `Or.inl : a → a ∨ b` and `Or.inr : b → a ∨ b`, and you can use `match` or `cases` to destruct an `Or` assumption into the two cases. ∃ half, Nat.succNat.succ (n : Nat) : NatThe successor function on natural numbers, `succ n = n + 1`. This is one of the two constructors of `Nat`. n'Nat = Eq.{u_1} {α : Sort u_1} (a✝a✝¹ : α) : PropThe equality relation. It has one introduction rule, `Eq.refl`. We use `a = b` as notation for `Eq a b`. A fundamental property of equality is that it is an equivalence relation. ``` variable (α : Type) (a b c d : α) variable (hab : a = b) (hcb : c = b) (hcd : c = d) example : a = d := Eq.trans (Eq.trans hab (Eq.symm hcb)) hcd ``` Equality is much more than an equivalence relation, however. It has the important property that every assertion respects the equivalence, in the sense that we can substitute equal expressions without changing the truth value. That is, given `h1 : a = b` and `h2 : p a`, we can construct a proof for `p b` using substitution: `Eq.subst h1 h2`. Example: ``` example (α : Type) (a b : α) (p : α → Prop) (h1 : a = b) (h2 : p a) : p b := Eq.subst h1 h2 example (α : Type) (a b : α) (p : α → Prop) (h1 : a = b) (h2 : p a) : p b := h1 ▸ h2 ``` The triangle in the second presentation is a macro built on top of `Eq.subst` and `Eq.symm`, and you can enter it by typing `\t`. For more information: [Equality](https://lean-lang.org/theorem_proving_in_lean4/quantifiers_and_equality.html#equality) 2 * HMul.hMul.{u, v, w} {α : Type u} {β : Type v} {γ : outParam (Type w)} [self : HMul α β γ] (a✝ : α) (a✝¹ : β) : γ`a * b` computes the product of `a` and `b`. The meaning of this notation is type-dependent. halfNat + HAdd.hAdd.{u, v, w} {α : Type u} {β : Type v} {γ : outParam (Type w)} [self : HAdd α β γ] (a✝ : α) (a✝¹ : β) : γ`a + b` computes the sum of `a` and `b`. The meaning of this notation is type-dependent. 1
succ.inr.intro.h
n'Nat:NatNat : TypeThe type of natural numbers, starting at zero. It is defined as an inductive type freely generated by "zero is a natural number" and "the successor of a natural number is a natural number". You can prove a theorem `P n` about `n : Nat` by `induction n`, which will expect a proof of the theorem for `P 0`, and a proof of `P (succ i)` assuming a proof of `P i`. The same method also works to define functions by recursion on natural numbers: induction and recursion are two expressions of the same operation from Lean's point of view. ``` open Nat example (n : Nat) : n < succ n := by induction n with | zero => show 0 < 1 decide | succ i ih => -- ih : i < succ i show succ i < succ (succ i) exact Nat.succ_lt_succ ih ``` This type is special-cased by both the kernel and the compiler: * The type of expressions contains "`Nat` literals" as a primitive constructor, and the kernel knows how to reduce zero/succ expressions to nat literals. * If implemented naively, this type would represent a numeral `n` in unary as a linked list with `n` links, which is horribly inefficient. Instead, the runtime itself has a special representation for `Nat` which stores numbers up to 2^63 directly and larger numbers use an arbitrary precision "bignum" library (usually [GMP](https://gmplib.org/)).
halfNat:NatNat : TypeThe type of natural numbers, starting at zero. It is defined as an inductive type freely generated by "zero is a natural number" and "the successor of a natural number is a natural number". You can prove a theorem `P n` about `n : Nat` by `induction n`, which will expect a proof of the theorem for `P 0`, and a proof of `P (succ i)` assuming a proof of `P i`. The same method also works to define functions by recursion on natural numbers: induction and recursion are two expressions of the same operation from Lean's point of view. ``` open Nat example (n : Nat) : n < succ n := by induction n with | zero => show 0 < 1 decide | succ i ih => -- ih : i < succ i show succ i < succ (succ i) exact Nat.succ_lt_succ ih ``` This type is special-cased by both the kernel and the compiler: * The type of expressions contains "`Nat` literals" as a primitive constructor, and the kernel knows how to reduce zero/succ expressions to nat literals. * If implemented naively, this type would represent a numeral `n` in unary as a linked list with `n` links, which is horribly inefficient. Instead, the runtime itself has a special representation for `Nat` which stores numbers up to 2^63 directly and larger numbers use an arbitrary precision "bignum" library (usually [GMP](https://gmplib.org/)).
prfn' = 2 * half + 1:n'Nat = Eq.{u_1} {α : Sort u_1} (a✝a✝¹ : α) : PropThe equality relation. It has one introduction rule, `Eq.refl`. We use `a = b` as notation for `Eq a b`. A fundamental property of equality is that it is an equivalence relation. ``` variable (α : Type) (a b c d : α) variable (hab : a = b) (hcb : c = b) (hcd : c = d) example : a = d := Eq.trans (Eq.trans hab (Eq.symm hcb)) hcd ``` Equality is much more than an equivalence relation, however. It has the important property that every assertion respects the equivalence, in the sense that we can substitute equal expressions without changing the truth value. That is, given `h1 : a = b` and `h2 : p a`, we can construct a proof for `p b` using substitution: `Eq.subst h1 h2`. Example: ``` example (α : Type) (a b : α) (p : α → Prop) (h1 : a = b) (h2 : p a) : p b := Eq.subst h1 h2 example (α : Type) (a b : α) (p : α → Prop) (h1 : a = b) (h2 : p a) : p b := h1 ▸ h2 ``` The triangle in the second presentation is a macro built on top of `Eq.subst` and `Eq.symm`, and you can enter it by typing `\t`. For more information: [Equality](https://lean-lang.org/theorem_proving_in_lean4/quantifiers_and_equality.html#equality) 2 * HMul.hMul.{u, v, w} {α : Type u} {β : Type v} {γ : outParam (Type w)} [self : HMul α β γ] (a✝ : α) (a✝¹ : β) : γ`a * b` computes the product of `a` and `b`. The meaning of this notation is type-dependent. halfNat + HAdd.hAdd.{u, v, w} {α : Type u} {β : Type v} {γ : outParam (Type w)} [self : HAdd α β γ] (a✝ : α) (a✝¹ : β) : γ`a + b` computes the sum of `a` and `b`. The meaning of this notation is type-dependent. 1
∃ half, Nat.succNat.succ (n : Nat) : NatThe successor function on natural numbers, `succ n = n + 1`. This is one of the two constructors of `Nat`. n'Nat = Eq.{u_1} {α : Sort u_1} (a✝a✝¹ : α) : PropThe equality relation. It has one introduction rule, `Eq.refl`. We use `a = b` as notation for `Eq a b`. A fundamental property of equality is that it is an equivalence relation. ``` variable (α : Type) (a b c d : α) variable (hab : a = b) (hcb : c = b) (hcd : c = d) example : a = d := Eq.trans (Eq.trans hab (Eq.symm hcb)) hcd ``` Equality is much more than an equivalence relation, however. It has the important property that every assertion respects the equivalence, in the sense that we can substitute equal expressions without changing the truth value. That is, given `h1 : a = b` and `h2 : p a`, we can construct a proof for `p b` using substitution: `Eq.subst h1 h2`. Example: ``` example (α : Type) (a b : α) (p : α → Prop) (h1 : a = b) (h2 : p a) : p b := Eq.subst h1 h2 example (α : Type) (a b : α) (p : α → Prop) (h1 : a = b) (h2 : p a) : p b := h1 ▸ h2 ``` The triangle in the second presentation is a macro built on top of `Eq.subst` and `Eq.symm`, and you can enter it by typing `\t`. For more information: [Equality](https://lean-lang.org/theorem_proving_in_lean4/quantifiers_and_equality.html#equality) 2 * HMul.hMul.{u, v, w} {α : Type u} {β : Type v} {γ : outParam (Type w)} [self : HMul α β γ] (a✝ : α) (a✝¹ : β) : γ`a * b` computes the product of `a` and `b`. The meaning of this notation is type-dependent. halfNat
succ.inr.intro.h
n'Nat:NatNat : TypeThe type of natural numbers, starting at zero. It is defined as an inductive type freely generated by "zero is a natural number" and "the successor of a natural number is a natural number". You can prove a theorem `P n` about `n : Nat` by `induction n`, which will expect a proof of the theorem for `P 0`, and a proof of `P (succ i)` assuming a proof of `P i`. The same method also works to define functions by recursion on natural numbers: induction and recursion are two expressions of the same operation from Lean's point of view. ``` open Nat example (n : Nat) : n < succ n := by induction n with | zero => show 0 < 1 decide | succ i ih => -- ih : i < succ i show succ i < succ (succ i) exact Nat.succ_lt_succ ih ``` This type is special-cased by both the kernel and the compiler: * The type of expressions contains "`Nat` literals" as a primitive constructor, and the kernel knows how to reduce zero/succ expressions to nat literals. * If implemented naively, this type would represent a numeral `n` in unary as a linked list with `n` links, which is horribly inefficient. Instead, the runtime itself has a special representation for `Nat` which stores numbers up to 2^63 directly and larger numbers use an arbitrary precision "bignum" library (usually [GMP](https://gmplib.org/)).
halfNat:NatNat : TypeThe type of natural numbers, starting at zero. It is defined as an inductive type freely generated by "zero is a natural number" and "the successor of a natural number is a natural number". You can prove a theorem `P n` about `n : Nat` by `induction n`, which will expect a proof of the theorem for `P 0`, and a proof of `P (succ i)` assuming a proof of `P i`. The same method also works to define functions by recursion on natural numbers: induction and recursion are two expressions of the same operation from Lean's point of view. ``` open Nat example (n : Nat) : n < succ n := by induction n with | zero => show 0 < 1 decide | succ i ih => -- ih : i < succ i show succ i < succ (succ i) exact Nat.succ_lt_succ ih ``` This type is special-cased by both the kernel and the compiler: * The type of expressions contains "`Nat` literals" as a primitive constructor, and the kernel knows how to reduce zero/succ expressions to nat literals. * If implemented naively, this type would represent a numeral `n` in unary as a linked list with `n` links, which is horribly inefficient. Instead, the runtime itself has a special representation for `Nat` which stores numbers up to 2^63 directly and larger numbers use an arbitrary precision "bignum" library (usually [GMP](https://gmplib.org/)).
prfn' = 2 * half + 1:n'Nat = Eq.{u_1} {α : Sort u_1} (a✝a✝¹ : α) : PropThe equality relation. It has one introduction rule, `Eq.refl`. We use `a = b` as notation for `Eq a b`. A fundamental property of equality is that it is an equivalence relation. ``` variable (α : Type) (a b c d : α) variable (hab : a = b) (hcb : c = b) (hcd : c = d) example : a = d := Eq.trans (Eq.trans hab (Eq.symm hcb)) hcd ``` Equality is much more than an equivalence relation, however. It has the important property that every assertion respects the equivalence, in the sense that we can substitute equal expressions without changing the truth value. That is, given `h1 : a = b` and `h2 : p a`, we can construct a proof for `p b` using substitution: `Eq.subst h1 h2`. Example: ``` example (α : Type) (a b : α) (p : α → Prop) (h1 : a = b) (h2 : p a) : p b := Eq.subst h1 h2 example (α : Type) (a b : α) (p : α → Prop) (h1 : a = b) (h2 : p a) : p b := h1 ▸ h2 ``` The triangle in the second presentation is a macro built on top of `Eq.subst` and `Eq.symm`, and you can enter it by typing `\t`. For more information: [Equality](https://lean-lang.org/theorem_proving_in_lean4/quantifiers_and_equality.html#equality) 2 * HMul.hMul.{u, v, w} {α : Type u} {β : Type v} {γ : outParam (Type w)} [self : HMul α β γ] (a✝ : α) (a✝¹ : β) : γ`a * b` computes the product of `a` and `b`. The meaning of this notation is type-dependent. halfNat + HAdd.hAdd.{u, v, w} {α : Type u} {β : Type v} {γ : outParam (Type w)} [self : HAdd α β γ] (a✝ : α) (a✝¹ : β) : γ`a + b` computes the sum of `a` and `b`. The meaning of this notation is type-dependent. 1
∃ half_1, Nat.succNat.succ (n : Nat) : NatThe successor function on natural numbers, `succ n = n + 1`. This is one of the two constructors of `Nat`. (2 * HMul.hMul.{u, v, w} {α : Type u} {β : Type v} {γ : outParam (Type w)} [self : HMul α β γ] (a✝ : α) (a✝¹ : β) : γ`a * b` computes the product of `a` and `b`. The meaning of this notation is type-dependent. halfNat + HAdd.hAdd.{u, v, w} {α : Type u} {β : Type v} {γ : outParam (Type w)} [self : HAdd α β γ] (a✝ : α) (a✝¹ : β) : γ`a + b` computes the sum of `a` and `b`. The meaning of this notation is type-dependent. 1) = Eq.{u_1} {α : Sort u_1} (a✝a✝¹ : α) : PropThe equality relation. It has one introduction rule, `Eq.refl`. We use `a = b` as notation for `Eq a b`. A fundamental property of equality is that it is an equivalence relation. ``` variable (α : Type) (a b c d : α) variable (hab : a = b) (hcb : c = b) (hcd : c = d) example : a = d := Eq.trans (Eq.trans hab (Eq.symm hcb)) hcd ``` Equality is much more than an equivalence relation, however. It has the important property that every assertion respects the equivalence, in the sense that we can substitute equal expressions without changing the truth value. That is, given `h1 : a = b` and `h2 : p a`, we can construct a proof for `p b` using substitution: `Eq.subst h1 h2`. Example: ``` example (α : Type) (a b : α) (p : α → Prop) (h1 : a = b) (h2 : p a) : p b := Eq.subst h1 h2 example (α : Type) (a b : α) (p : α → Prop) (h1 : a = b) (h2 : p a) : p b := h1 ▸ h2 ``` The triangle in the second presentation is a macro built on top of `Eq.subst` and `Eq.symm`, and you can enter it by typing `\t`. For more information: [Equality](https://lean-lang.org/theorem_proving_in_lean4/quantifiers_and_equality.html#equality) 2 * HMul.hMul.{u, v, w} {α : Type u} {β : Type v} {γ : outParam (Type w)} [self : HMul α β γ] (a✝ : α) (a✝¹ : β) : γ`a * b` computes the product of `a` and `b`. The meaning of this notation is type-dependent. half_1Nat
All goals completed! 🐙

The pattern language for rcases is described in more detail in its docstring.

Extensionality

The ext tactic, by Simon Hudon, applies an extensionality lemma to the current goal. Extensionality lemmas characterize the equality of two objects by the observations that can be made on them; for functions, extensionality means that they map equal inputs to equal outputs, while for structures, extensionality means that their fields are equal.

Lemmas marked with the @[ext] attribute are added to the database that the ext tactic searches. Furthermore, applying @[ext] to a structure definition arranges for an appropriate extensionality lemma for the structure type to be stated, proved, and added to the database. In the following example, the attribute generates the lemma for BoundsBounds : Type:

@[extRegisters an extensionality theorem. * When `@[ext]` is applied to a structure, it generates `.ext` and `.ext_iff` theorems and registers them for the `ext` tactic. * When `@[ext]` is applied to a theorem, the theorem is registered for the `ext` tactic. * An optional natural number argument, e.g. `@[ext 9000]`, specifies a priority for the lemma. Higher-priority lemmas are chosen first, and the default is `1000`. * The flag `@[ext (flat := false)]` causes generated structure extensionality theorems to show inherited fields based on their representation, rather than flattening the parents' fields into the lemma's equality hypotheses. structures in the generated extensionality theorems. ] structure BoundsBounds : Type where lowerBounds.lower (self : Bounds) : Nat : NatNat : TypeThe type of natural numbers, starting at zero. It is defined as an inductive type freely generated by "zero is a natural number" and "the successor of a natural number is a natural number". You can prove a theorem `P n` about `n : Nat` by `induction n`, which will expect a proof of the theorem for `P 0`, and a proof of `P (succ i)` assuming a proof of `P i`. The same method also works to define functions by recursion on natural numbers: induction and recursion are two expressions of the same operation from Lean's point of view. ``` open Nat example (n : Nat) : n < succ n := by induction n with | zero => show 0 < 1 decide | succ i ih => -- ih : i < succ i show succ i < succ (succ i) exact Nat.succ_lt_succ ih ``` This type is special-cased by both the kernel and the compiler: * The type of expressions contains "`Nat` literals" as a primitive constructor, and the kernel knows how to reduce zero/succ expressions to nat literals. * If implemented naively, this type would represent a numeral `n` in unary as a linked list with `n` links, which is horribly inefficient. Instead, the runtime itself has a special representation for `Nat` which stores numbers up to 2^63 directly and larger numbers use an arbitrary precision "bignum" library (usually [GMP](https://gmplib.org/)). upperBounds.upper (self : Bounds) : Nat : NatNat : TypeThe type of natural numbers, starting at zero. It is defined as an inductive type freely generated by "zero is a natural number" and "the successor of a natural number is a natural number". You can prove a theorem `P n` about `n : Nat` by `induction n`, which will expect a proof of the theorem for `P 0`, and a proof of `P (succ i)` assuming a proof of `P i`. The same method also works to define functions by recursion on natural numbers: induction and recursion are two expressions of the same operation from Lean's point of view. ``` open Nat example (n : Nat) : n < succ n := by induction n with | zero => show 0 < 1 decide | succ i ih => -- ih : i < succ i show succ i < succ (succ i) exact Nat.succ_lt_succ ih ``` This type is special-cased by both the kernel and the compiler: * The type of expressions contains "`Nat` literals" as a primitive constructor, and the kernel knows how to reduce zero/succ expressions to nat literals. * If implemented naively, this type would represent a numeral `n` in unary as a linked list with `n` links, which is horribly inefficient. Instead, the runtime itself has a special representation for `Nat` which stores numbers up to 2^63 directly and larger numbers use an arbitrary precision "bignum" library (usually [GMP](https://gmplib.org/)). okBounds.ok (self : Bounds) : self.lower < self.upper : lowerNat < upperNat

While the following instances of BoundsBounds : Type are already definitionally equal, ext can be used to prove their equality:

def bOne_root_.bOne : Bounds : BoundsBounds : Type := 1, 4,
1 < LT.lt.{u} {α : Type u} [self : LT α] (a✝a✝¹ : α) : PropThe less-than relation: `x < y` 4
All goals completed! 🐙
def bTwo_root_.bTwo : Bounds : BoundsBounds : Type where lowerNat := Nat.succNat.succ (n : Nat) : NatThe successor function on natural numbers, `succ n = n + 1`. This is one of the two constructors of `Nat`. Nat.zeroNat.zero : Nat`Nat.zero`, normally written `0 : Nat`, is the smallest natural number. This is one of the two constructors of `Nat`. upperNat := 2 + 2 okNat.succ Nat.zero < 2 + 2 := Nat.lt_of_sub_eq_succNat.lt_of_sub_eq_succ {m n l : Nat} (h : m - n = Nat.succ l) : n < m rflrfl.{u} {α : Sort u} {a : α} : a = a`rfl : a = a` is the unique constructor of the equality type. This is the same as `Eq.refl` except that it takes `a` implicitly instead of explicitly. This is a more powerful theorem than it may appear at first, because although the statement of the theorem is `a = a`, Lean will allow anything that is definitionally equal to that type. So, for instance, `2 + 2 = 4` is proven in Lean by `rfl`, because both sides are the same up to definitional equality.

Applying the ext tactic to this goal gives two new goals, one for each non-proof field:

theorem bOne_eq_bTwo_root_.bOne_eq_bTwo : bOne = bTwo : bOnebOne : Bounds = bTwobTwo : Bounds :=
bOnebOne : Bounds = Eq.{u_1} {α : Sort u_1} (a✝a✝¹ : α) : PropThe equality relation. It has one introduction rule, `Eq.refl`. We use `a = b` as notation for `Eq a b`. A fundamental property of equality is that it is an equivalence relation. ``` variable (α : Type) (a b c d : α) variable (hab : a = b) (hcb : c = b) (hcd : c = d) example : a = d := Eq.trans (Eq.trans hab (Eq.symm hcb)) hcd ``` Equality is much more than an equivalence relation, however. It has the important property that every assertion respects the equivalence, in the sense that we can substitute equal expressions without changing the truth value. That is, given `h1 : a = b` and `h2 : p a`, we can construct a proof for `p b` using substitution: `Eq.subst h1 h2`. Example: ``` example (α : Type) (a b : α) (p : α → Prop) (h1 : a = b) (h2 : p a) : p b := Eq.subst h1 h2 example (α : Type) (a b : α) (p : α → Prop) (h1 : a = b) (h2 : p a) : p b := h1 ▸ h2 ``` The triangle in the second presentation is a macro built on top of `Eq.subst` and `Eq.symm`, and you can enter it by typing `\t`. For more information: [Equality](https://lean-lang.org/theorem_proving_in_lean4/quantifiers_and_equality.html#equality) bTwobTwo : Bounds
lowerbOnebOne : Bounds.lower = Eq.{u_1} {α : Sort u_1} (a✝a✝¹ : α) : PropThe equality relation. It has one introduction rule, `Eq.refl`. We use `a = b` as notation for `Eq a b`. A fundamental property of equality is that it is an equivalence relation. ``` variable (α : Type) (a b c d : α) variable (hab : a = b) (hcb : c = b) (hcd : c = d) example : a = d := Eq.trans (Eq.trans hab (Eq.symm hcb)) hcd ``` Equality is much more than an equivalence relation, however. It has the important property that every assertion respects the equivalence, in the sense that we can substitute equal expressions without changing the truth value. That is, given `h1 : a = b` and `h2 : p a`, we can construct a proof for `p b` using substitution: `Eq.subst h1 h2`. Example: ``` example (α : Type) (a b : α) (p : α → Prop) (h1 : a = b) (h2 : p a) : p b := Eq.subst h1 h2 example (α : Type) (a b : α) (p : α → Prop) (h1 : a = b) (h2 : p a) : p b := h1 ▸ h2 ``` The triangle in the second presentation is a macro built on top of `Eq.subst` and `Eq.symm`, and you can enter it by typing `\t`. For more information: [Equality](https://lean-lang.org/theorem_proving_in_lean4/quantifiers_and_equality.html#equality) bTwobTwo : Bounds.lower
upperbOnebOne : Bounds.upper = Eq.{u_1} {α : Sort u_1} (a✝a✝¹ : α) : PropThe equality relation. It has one introduction rule, `Eq.refl`. We use `a = b` as notation for `Eq a b`. A fundamental property of equality is that it is an equivalence relation. ``` variable (α : Type) (a b c d : α) variable (hab : a = b) (hcb : c = b) (hcd : c = d) example : a = d := Eq.trans (Eq.trans hab (Eq.symm hcb)) hcd ``` Equality is much more than an equivalence relation, however. It has the important property that every assertion respects the equivalence, in the sense that we can substitute equal expressions without changing the truth value. That is, given `h1 : a = b` and `h2 : p a`, we can construct a proof for `p b` using substitution: `Eq.subst h1 h2`. Example: ``` example (α : Type) (a b : α) (p : α → Prop) (h1 : a = b) (h2 : p a) : p b := Eq.subst h1 h2 example (α : Type) (a b : α) (p : α → Prop) (h1 : a = b) (h2 : p a) : p b := h1 ▸ h2 ``` The triangle in the second presentation is a macro built on top of `Eq.subst` and `Eq.symm`, and you can enter it by typing `\t`. For more information: [Equality](https://lean-lang.org/theorem_proving_in_lean4/quantifiers_and_equality.html#equality) bTwobTwo : Bounds.upper
unsolved goals
case lower
⊢ bOne.lower = bTwo.lower

case upper
⊢ bOne.upper = bTwo.upper

Simplifier Suggestions

The simp? tactic runs simp as usual, but it tracks which lemmas were used. It then suggests replacing the call with an invocation of simp only. Using a minimal set of simp lemmas can make proofs faster to check, and it can also make them more robust to changes in the set of default simp lemmas. Generally, it's a good idea to ensure that all uses of simp that don't close the current goal take a restricted set of lemmas, which improves the robustness of the proofs.

Proof by Cases

With classical logic, showing that P \to Q and \neg P \to Q is sufficient to show Q. The by_cases tactic captures this pattern of reasoning: by_cases P results in two subgoals, one with an assumption of P and one with an assumption of ¬P.

Cast Normalization

Lean's coercion mechanism makes it easy to combine terms with different types, but the resulting term will include calls to the functions that perform the conversion. When writing proofs, these essentially bureaucratic details can get in the way, and working to manually remove them is tedious.

The norm_cast tactic performs rewrites to put these casts in a normal form, making more terms definitionally equal. It was originally developed for Lean 3 by Robert Y. Lewis and Paul-Nicolas Madelaine.

Changing Types

The change tactic replaces the goal or a hypothesis with one that is definitionally equal, accepting as its argument a pattern that the resulting goal or hypothesis type should match. Underscores in the pattern represent terms to be filled out by unification.

For instance, given this function that splits a list into two sublists:

def splitsplit.{u_1} {α : Type u_1} (a✝ : List α) : List α × List α : ListList.{u} (α : Type u) : Type u`List α` is the type of ordered lists with elements of type `α`. It is implemented as a linked list. `List α` is isomorphic to `Array α`, but they are useful for different things: * `List α` is easier for reasoning, and `Array α` is modeled as a wrapper around `List α` * `List α` works well as a persistent data structure, when many copies of the tail are shared. When the value is not shared, `Array α` will have better performance because it can do destructive updates. αType u_1 ListList.{u} (α : Type u) : Type u`List α` is the type of ordered lists with elements of type `α`. It is implemented as a linked list. `List α` is isomorphic to `Array α`, but they are useful for different things: * `List α` is easier for reasoning, and `Array α` is modeled as a wrapper around `List α` * `List α` works well as a persistent data structure, when many copies of the tail are shared. When the value is not shared, `Array α` will have better performance because it can do destructive updates. αType u_1 × ListList.{u} (α : Type u) : Type u`List α` is the type of ordered lists with elements of type `α`. It is implemented as a linked list. `List α` is isomorphic to `Array α`, but they are useful for different things: * `List α` is easier for reasoning, and `Array α` is modeled as a wrapper around `List α` * `List α` works well as a persistent data structure, when many copies of the tail are shared. When the value is not shared, `Array α` will have better performance because it can do destructive updates. αType u_1 | [] => ([], []) | [xα] => ([xα], []) | xα :: x'α :: xsList α => let`let` is used to declare a local definition. Example: ``` let x := 1 let y := x + 1 x + y ``` Since functions are first class citizens in Lean, you can use `let` to declare local functions too. ``` let double := fun x => 2*x double (double 3) ``` For recursive definitions, you should use `let rec`. You can also perform pattern matching using `let`. For example, assume `p` has type `Nat × Nat`, then you can write ``` let (x, y) := p x + y ``` (preList α, postList α) := splitsplit.{u_1} {α : Type u_1} (a✝ : List α) : List α × List α xsList α (xα :: preList α, x'α :: postList α)

it may be useful to prove that the resulting pair of lists has as many entries as the original list:

theorem split_lengthsplit_length.{u_1} {α : Type u_1} (xs : List α) : List.length (split xs).fst + List.length (split xs).snd = List.length xs (xsList α : ListList.{u} (α : Type u) : Type u`List α` is the type of ordered lists with elements of type `α`. It is implemented as a linked list. `List α` is isomorphic to `Array α`, but they are useful for different things: * `List α` is easier for reasoning, and `Array α` is modeled as a wrapper around `List α` * `List α` works well as a persistent data structure, when many copies of the tail are shared. When the value is not shared, `Array α` will have better performance because it can do destructive updates. αType u_1) : (splitsplit.{u_1} {α : Type u_1} (a✝ : List α) : List α × List α xsList α).fstProd.fst.{u, v} {α : Type u} {β : Type v} (self : α × β) : αThe first projection out of a pair. if `p : α × β` then `p.1 : α`. .lengthList.length.{u_1} {α : Type u_1} (a✝ : List α) : NatThe length of a list: `[].length = 0` and `(a :: l).length = l.length + 1`. This function is overridden in the compiler to `lengthTR`, which uses constant stack space, while leaving this function to use the "naive" recursion which is easier for reasoning. + (splitsplit.{u_1} {α : Type u_1} (a✝ : List α) : List α × List α xsList α).sndProd.snd.{u, v} {α : Type u} {β : Type v} (self : α × β) : βThe second projection out of a pair. if `p : α × β` then `p.2 : β`. .lengthList.length.{u_1} {α : Type u_1} (a✝ : List α) : NatThe length of a list: `[].length = 0` and `(a :: l).length = l.length + 1`. This function is overridden in the compiler to `lengthTR`, which uses constant stack space, while leaving this function to use the "naive" recursion which is easier for reasoning. = xsList α.lengthList.length.{u_1} {α : Type u_1} (a✝ : List α) : NatThe length of a list: `[].length = 0` and `(a :: l).length = l.length + 1`. This function is overridden in the compiler to `lengthTR`, which uses constant stack space, while leaving this function to use the "naive" recursion which is easier for reasoning. :=
αType u_1:Type u_1
xsList α:ListList.{u} (α : Type u) : Type u`List α` is the type of ordered lists with elements of type `α`. It is implemented as a linked list. `List α` is isomorphic to `Array α`, but they are useful for different things: * `List α` is easier for reasoning, and `Array α` is modeled as a wrapper around `List α` * `List α` works well as a persistent data structure, when many copies of the tail are shared. When the value is not shared, `Array α` will have better performance because it can do destructive updates. αType u_1
List.lengthList.length.{u_1} {α : Type u_1} (a✝ : List α) : NatThe length of a list: `[].length = 0` and `(a :: l).length = l.length + 1`. This function is overridden in the compiler to `lengthTR`, which uses constant stack space, while leaving this function to use the "naive" recursion which is easier for reasoning. (splitsplit.{u_1} {α : Type u_1} (a✝ : List α) : List α × List α xsList α).fst + HAdd.hAdd.{u, v, w} {α : Type u} {β : Type v} {γ : outParam (Type w)} [self : HAdd α β γ] (a✝ : α) (a✝¹ : β) : γ`a + b` computes the sum of `a` and `b`. The meaning of this notation is type-dependent. List.lengthList.length.{u_1} {α : Type u_1} (a✝ : List α) : NatThe length of a list: `[].length = 0` and `(a :: l).length = l.length + 1`. This function is overridden in the compiler to `lengthTR`, which uses constant stack space, while leaving this function to use the "naive" recursion which is easier for reasoning. (splitsplit.{u_1} {α : Type u_1} (a✝ : List α) : List α × List α xsList α).snd = Eq.{u_1} {α : Sort u_1} (a✝a✝¹ : α) : PropThe equality relation. It has one introduction rule, `Eq.refl`. We use `a = b` as notation for `Eq a b`. A fundamental property of equality is that it is an equivalence relation. ``` variable (α : Type) (a b c d : α) variable (hab : a = b) (hcb : c = b) (hcd : c = d) example : a = d := Eq.trans (Eq.trans hab (Eq.symm hcb)) hcd ``` Equality is much more than an equivalence relation, however. It has the important property that every assertion respects the equivalence, in the sense that we can substitute equal expressions without changing the truth value. That is, given `h1 : a = b` and `h2 : p a`, we can construct a proof for `p b` using substitution: `Eq.subst h1 h2`. Example: ``` example (α : Type) (a b : α) (p : α → Prop) (h1 : a = b) (h2 : p a) : p b := Eq.subst h1 h2 example (α : Type) (a b : α) (p : α → Prop) (h1 : a = b) (h2 : p a) : p b := h1 ▸ h2 ``` The triangle in the second presentation is a macro built on top of `Eq.subst` and `Eq.symm`, and you can enter it by typing `\t`. For more information: [Equality](https://lean-lang.org/theorem_proving_in_lean4/quantifiers_and_equality.html#equality) List.lengthList.length.{u_1} {α : Type u_1} (a✝ : List α) : NatThe length of a list: `[].length = 0` and `(a :: l).length = l.length + 1`. This function is overridden in the compiler to `lengthTR`, which uses constant stack space, while leaving this function to use the "naive" recursion which is easier for reasoning. xsList α
match`match` performs case analysis on one or more expressions. See [Induction and Recursion][tpil4]. The syntax for the `match` tactic is the same as term-mode `match`, except that the match arms are tactics instead of expressions. ``` example (n : Nat) : n = n := by match n with | 0 => rfl | i+1 => simp ``` [tpil4]: https://lean-lang.org/theorem_proving_in_lean4/induction_and_recursion.html xsList α with`match` performs case analysis on one or more expressions. See [Induction and Recursion][tpil4]. The syntax for the `match` tactic is the same as term-mode `match`, except that the match arms are tactics instead of expressions. ``` example (n : Nat) : n = n := by match n with | 0 => rfl | i+1 => simp ``` [tpil4]: https://lean-lang.org/theorem_proving_in_lean4/induction_and_recursion.html | [] =>
All goals completed! 🐙
| [yα] =>
All goals completed! 🐙
| yα :: y'α :: ysList α unsolved goals α : Type u_1 xs : List α y y' : α ys : List α this : List.length (split ys).fst + List.length (split ys).snd = List.length ys ⊢ List.length (split (y :: y' :: ys)).fst + List.length (split (y :: y' :: ys)).snd = List.length (y :: y' :: ys)=>
αType u_1:Type u_1
xsList α:ListList.{u} (α : Type u) : Type u`List α` is the type of ordered lists with elements of type `α`. It is implemented as a linked list. `List α` is isomorphic to `Array α`, but they are useful for different things: * `List α` is easier for reasoning, and `Array α` is modeled as a wrapper around `List α` * `List α` works well as a persistent data structure, when many copies of the tail are shared. When the value is not shared, `Array α` will have better performance because it can do destructive updates. αType u_1
yα:αType u_1
y'α:αType u_1
ysList α:ListList.{u} (α : Type u) : Type u`List α` is the type of ordered lists with elements of type `α`. It is implemented as a linked list. `List α` is isomorphic to `Array α`, but they are useful for different things: * `List α` is easier for reasoning, and `Array α` is modeled as a wrapper around `List α` * `List α` works well as a persistent data structure, when many copies of the tail are shared. When the value is not shared, `Array α` will have better performance because it can do destructive updates. αType u_1
thisList.length (split ys).fst + List.length (split ys).snd = List.length ys:List.lengthList.length.{u_1} {α : Type u_1} (a✝ : List α) : NatThe length of a list: `[].length = 0` and `(a :: l).length = l.length + 1`. This function is overridden in the compiler to `lengthTR`, which uses constant stack space, while leaving this function to use the "naive" recursion which is easier for reasoning. (splitsplit.{u_1} {α : Type u_1} (a✝ : List α) : List α × List α ysList α).fst + HAdd.hAdd.{u, v, w} {α : Type u} {β : Type v} {γ : outParam (Type w)} [self : HAdd α β γ] (a✝ : α) (a✝¹ : β) : γ`a + b` computes the sum of `a` and `b`. The meaning of this notation is type-dependent. List.lengthList.length.{u_1} {α : Type u_1} (a✝ : List α) : NatThe length of a list: `[].length = 0` and `(a :: l).length = l.length + 1`. This function is overridden in the compiler to `lengthTR`, which uses constant stack space, while leaving this function to use the "naive" recursion which is easier for reasoning. (splitsplit.{u_1} {α : Type u_1} (a✝ : List α) : List α × List α ysList α).snd = Eq.{u_1} {α : Sort u_1} (a✝a✝¹ : α) : PropThe equality relation. It has one introduction rule, `Eq.refl`. We use `a = b` as notation for `Eq a b`. A fundamental property of equality is that it is an equivalence relation. ``` variable (α : Type) (a b c d : α) variable (hab : a = b) (hcb : c = b) (hcd : c = d) example : a = d := Eq.trans (Eq.trans hab (Eq.symm hcb)) hcd ``` Equality is much more than an equivalence relation, however. It has the important property that every assertion respects the equivalence, in the sense that we can substitute equal expressions without changing the truth value. That is, given `h1 : a = b` and `h2 : p a`, we can construct a proof for `p b` using substitution: `Eq.subst h1 h2`. Example: ``` example (α : Type) (a b : α) (p : α → Prop) (h1 : a = b) (h2 : p a) : p b := Eq.subst h1 h2 example (α : Type) (a b : α) (p : α → Prop) (h1 : a = b) (h2 : p a) : p b := h1 ▸ h2 ``` The triangle in the second presentation is a macro built on top of `Eq.subst` and `Eq.symm`, and you can enter it by typing `\t`. For more information: [Equality](https://lean-lang.org/theorem_proving_in_lean4/quantifiers_and_equality.html#equality) List.lengthList.length.{u_1} {α : Type u_1} (a✝ : List α) : NatThe length of a list: `[].length = 0` and `(a :: l).length = l.length + 1`. This function is overridden in the compiler to `lengthTR`, which uses constant stack space, while leaving this function to use the "naive" recursion which is easier for reasoning. ysList α
List.lengthList.length.{u_1} {α : Type u_1} (a✝ : List α) : NatThe length of a list: `[].length = 0` and `(a :: l).length = l.length + 1`. This function is overridden in the compiler to `lengthTR`, which uses constant stack space, while leaving this function to use the "naive" recursion which is easier for reasoning. (splitsplit.{u_1} {α : Type u_1} (a✝ : List α) : List α × List α (yα :: List.cons.{u} {α : Type u} (head : α) (tail : List α) : List αIf `a : α` and `l : List α`, then `cons a l`, or `a :: l`, is the list whose first element is `a` and with `l` as the rest of the list. y'α :: List.cons.{u} {α : Type u} (head : α) (tail : List α) : List αIf `a : α` and `l : List α`, then `cons a l`, or `a :: l`, is the list whose first element is `a` and with `l` as the rest of the list. ysList α)).fst + HAdd.hAdd.{u, v, w} {α : Type u} {β : Type v} {γ : outParam (Type w)} [self : HAdd α β γ] (a✝ : α) (a✝¹ : β) : γ`a + b` computes the sum of `a` and `b`. The meaning of this notation is type-dependent. List.lengthList.length.{u_1} {α : Type u_1} (a✝ : List α) : NatThe length of a list: `[].length = 0` and `(a :: l).length = l.length + 1`. This function is overridden in the compiler to `lengthTR`, which uses constant stack space, while leaving this function to use the "naive" recursion which is easier for reasoning. (splitsplit.{u_1} {α : Type u_1} (a✝ : List α) : List α × List α (yα :: List.cons.{u} {α : Type u} (head : α) (tail : List α) : List αIf `a : α` and `l : List α`, then `cons a l`, or `a :: l`, is the list whose first element is `a` and with `l` as the rest of the list. y'α :: List.cons.{u} {α : Type u} (head : α) (tail : List α) : List αIf `a : α` and `l : List α`, then `cons a l`, or `a :: l`, is the list whose first element is `a` and with `l` as the rest of the list. ysList α)).snd = Eq.{u_1} {α : Sort u_1} (a✝a✝¹ : α) : PropThe equality relation. It has one introduction rule, `Eq.refl`. We use `a = b` as notation for `Eq a b`. A fundamental property of equality is that it is an equivalence relation. ``` variable (α : Type) (a b c d : α) variable (hab : a = b) (hcb : c = b) (hcd : c = d) example : a = d := Eq.trans (Eq.trans hab (Eq.symm hcb)) hcd ``` Equality is much more than an equivalence relation, however. It has the important property that every assertion respects the equivalence, in the sense that we can substitute equal expressions without changing the truth value. That is, given `h1 : a = b` and `h2 : p a`, we can construct a proof for `p b` using substitution: `Eq.subst h1 h2`. Example: ``` example (α : Type) (a b : α) (p : α → Prop) (h1 : a = b) (h2 : p a) : p b := Eq.subst h1 h2 example (α : Type) (a b : α) (p : α → Prop) (h1 : a = b) (h2 : p a) : p b := h1 ▸ h2 ``` The triangle in the second presentation is a macro built on top of `Eq.subst` and `Eq.symm`, and you can enter it by typing `\t`. For more information: [Equality](https://lean-lang.org/theorem_proving_in_lean4/quantifiers_and_equality.html#equality) List.lengthList.length.{u_1} {α : Type u_1} (a✝ : List α) : NatThe length of a list: `[].length = 0` and `(a :: l).length = l.length + 1`. This function is overridden in the compiler to `lengthTR`, which uses constant stack space, while leaving this function to use the "naive" recursion which is easier for reasoning. (yα :: List.cons.{u} {α : Type u} (head : α) (tail : List α) : List αIf `a : α` and `l : List α`, then `cons a l`, or `a :: l`, is the list whose first element is `a` and with `l` as the rest of the list. y'α :: List.cons.{u} {α : Type u} (head : α) (tail : List α) : List αIf `a : α` and `l : List α`, then `cons a l`, or `a :: l`, is the list whose first element is `a` and with `l` as the rest of the list. ysList α)

At this point in the proof, the unsolved goal is not yet in a form suitable for omega:

unsolved goals
α : Type u_1
xs : List α
y y' : α
ys : List α
this : List.length (split ys).fst + List.length (split ys).snd = List.length ys
⊢ List.length (split (y :: y' :: ys)).fst + List.length (split (y :: y' :: ys)).snd = List.length (y :: y' :: ys)

Invoking the change tactic with a pattern that exposes the additions that result from the calls to List.lengthList.length.{u_1} {α : Type u_1} (a✝ : List α) : NatThe length of a list: `[].length = 0` and `(a :: l).length = l.length + 1`. This function is overridden in the compiler to `lengthTR`, which uses constant stack space, while leaving this function to use the "naive" recursion which is easier for reasoning. results in a goal that is suitable for omega:

theorem split_lengthsplit_length.{u_1} {α : Type u_1} (xs : List α) : List.length (split xs).fst + List.length (split xs).snd = List.length xs (xsList α : ListList.{u} (α : Type u) : Type u`List α` is the type of ordered lists with elements of type `α`. It is implemented as a linked list. `List α` is isomorphic to `Array α`, but they are useful for different things: * `List α` is easier for reasoning, and `Array α` is modeled as a wrapper around `List α` * `List α` works well as a persistent data structure, when many copies of the tail are shared. When the value is not shared, `Array α` will have better performance because it can do destructive updates. αType u_1) : (splitsplit.{u_1} {α : Type u_1} (a✝ : List α) : List α × List α xsList α).fstProd.fst.{u, v} {α : Type u} {β : Type v} (self : α × β) : αThe first projection out of a pair. if `p : α × β` then `p.1 : α`. .lengthList.length.{u_1} {α : Type u_1} (a✝ : List α) : NatThe length of a list: `[].length = 0` and `(a :: l).length = l.length + 1`. This function is overridden in the compiler to `lengthTR`, which uses constant stack space, while leaving this function to use the "naive" recursion which is easier for reasoning. + (splitsplit.{u_1} {α : Type u_1} (a✝ : List α) : List α × List α xsList α).sndProd.snd.{u, v} {α : Type u} {β : Type v} (self : α × β) : βThe second projection out of a pair. if `p : α × β` then `p.2 : β`. .lengthList.length.{u_1} {α : Type u_1} (a✝ : List α) : NatThe length of a list: `[].length = 0` and `(a :: l).length = l.length + 1`. This function is overridden in the compiler to `lengthTR`, which uses constant stack space, while leaving this function to use the "naive" recursion which is easier for reasoning. = xsList α.lengthList.length.{u_1} {α : Type u_1} (a✝ : List α) : NatThe length of a list: `[].length = 0` and `(a :: l).length = l.length + 1`. This function is overridden in the compiler to `lengthTR`, which uses constant stack space, while leaving this function to use the "naive" recursion which is easier for reasoning. :=
αType u_1:Type u_1
xsList α:ListList.{u} (α : Type u) : Type u`List α` is the type of ordered lists with elements of type `α`. It is implemented as a linked list. `List α` is isomorphic to `Array α`, but they are useful for different things: * `List α` is easier for reasoning, and `Array α` is modeled as a wrapper around `List α` * `List α` works well as a persistent data structure, when many copies of the tail are shared. When the value is not shared, `Array α` will have better performance because it can do destructive updates. αType u_1
List.lengthList.length.{u_1} {α : Type u_1} (a✝ : List α) : NatThe length of a list: `[].length = 0` and `(a :: l).length = l.length + 1`. This function is overridden in the compiler to `lengthTR`, which uses constant stack space, while leaving this function to use the "naive" recursion which is easier for reasoning. (splitsplit.{u_1} {α : Type u_1} (a✝ : List α) : List α × List α xsList α).fst + HAdd.hAdd.{u, v, w} {α : Type u} {β : Type v} {γ : outParam (Type w)} [self : HAdd α β γ] (a✝ : α) (a✝¹ : β) : γ`a + b` computes the sum of `a` and `b`. The meaning of this notation is type-dependent. List.lengthList.length.{u_1} {α : Type u_1} (a✝ : List α) : NatThe length of a list: `[].length = 0` and `(a :: l).length = l.length + 1`. This function is overridden in the compiler to `lengthTR`, which uses constant stack space, while leaving this function to use the "naive" recursion which is easier for reasoning. (splitsplit.{u_1} {α : Type u_1} (a✝ : List α) : List α × List α xsList α).snd = Eq.{u_1} {α : Sort u_1} (a✝a✝¹ : α) : PropThe equality relation. It has one introduction rule, `Eq.refl`. We use `a = b` as notation for `Eq a b`. A fundamental property of equality is that it is an equivalence relation. ``` variable (α : Type) (a b c d : α) variable (hab : a = b) (hcb : c = b) (hcd : c = d) example : a = d := Eq.trans (Eq.trans hab (Eq.symm hcb)) hcd ``` Equality is much more than an equivalence relation, however. It has the important property that every assertion respects the equivalence, in the sense that we can substitute equal expressions without changing the truth value. That is, given `h1 : a = b` and `h2 : p a`, we can construct a proof for `p b` using substitution: `Eq.subst h1 h2`. Example: ``` example (α : Type) (a b : α) (p : α → Prop) (h1 : a = b) (h2 : p a) : p b := Eq.subst h1 h2 example (α : Type) (a b : α) (p : α → Prop) (h1 : a = b) (h2 : p a) : p b := h1 ▸ h2 ``` The triangle in the second presentation is a macro built on top of `Eq.subst` and `Eq.symm`, and you can enter it by typing `\t`. For more information: [Equality](https://lean-lang.org/theorem_proving_in_lean4/quantifiers_and_equality.html#equality) List.lengthList.length.{u_1} {α : Type u_1} (a✝ : List α) : NatThe length of a list: `[].length = 0` and `(a :: l).length = l.length + 1`. This function is overridden in the compiler to `lengthTR`, which uses constant stack space, while leaving this function to use the "naive" recursion which is easier for reasoning. xsList α
match`match` performs case analysis on one or more expressions. See [Induction and Recursion][tpil4]. The syntax for the `match` tactic is the same as term-mode `match`, except that the match arms are tactics instead of expressions. ``` example (n : Nat) : n = n := by match n with | 0 => rfl | i+1 => simp ``` [tpil4]: https://lean-lang.org/theorem_proving_in_lean4/induction_and_recursion.html xsList α with`match` performs case analysis on one or more expressions. See [Induction and Recursion][tpil4]. The syntax for the `match` tactic is the same as term-mode `match`, except that the match arms are tactics instead of expressions. ``` example (n : Nat) : n = n := by match n with | 0 => rfl | i+1 => simp ``` [tpil4]: https://lean-lang.org/theorem_proving_in_lean4/induction_and_recursion.html | [] =>
All goals completed! 🐙
| [yα] =>
All goals completed! 🐙
| yα :: y'α :: ysList α unsolved goals α : Type u_1 xs : List α y y' : α ys : List α this : List.length (split ys).fst + List.length (split ys).snd = List.length ys ⊢ List.length (split ys).fst + 1 + List.length (split ys).snd + 1 = List.length ys + 2=>
αType u_1:Type u_1
xsList α:ListList.{u} (α : Type u) : Type u`List α` is the type of ordered lists with elements of type `α`. It is implemented as a linked list. `List α` is isomorphic to `Array α`, but they are useful for different things: * `List α` is easier for reasoning, and `Array α` is modeled as a wrapper around `List α` * `List α` works well as a persistent data structure, when many copies of the tail are shared. When the value is not shared, `Array α` will have better performance because it can do destructive updates. αType u_1
yα:αType u_1
y'α:αType u_1
ysList α:ListList.{u} (α : Type u) : Type u`List α` is the type of ordered lists with elements of type `α`. It is implemented as a linked list. `List α` is isomorphic to `Array α`, but they are useful for different things: * `List α` is easier for reasoning, and `Array α` is modeled as a wrapper around `List α` * `List α` works well as a persistent data structure, when many copies of the tail are shared. When the value is not shared, `Array α` will have better performance because it can do destructive updates. αType u_1
thisList.length (split ys).fst + List.length (split ys).snd = List.length ys:List.lengthList.length.{u_1} {α : Type u_1} (a✝ : List α) : NatThe length of a list: `[].length = 0` and `(a :: l).length = l.length + 1`. This function is overridden in the compiler to `lengthTR`, which uses constant stack space, while leaving this function to use the "naive" recursion which is easier for reasoning. (splitsplit.{u_1} {α : Type u_1} (a✝ : List α) : List α × List α ysList α).fst + HAdd.hAdd.{u, v, w} {α : Type u} {β : Type v} {γ : outParam (Type w)} [self : HAdd α β γ] (a✝ : α) (a✝¹ : β) : γ`a + b` computes the sum of `a` and `b`. The meaning of this notation is type-dependent. List.lengthList.length.{u_1} {α : Type u_1} (a✝ : List α) : NatThe length of a list: `[].length = 0` and `(a :: l).length = l.length + 1`. This function is overridden in the compiler to `lengthTR`, which uses constant stack space, while leaving this function to use the "naive" recursion which is easier for reasoning. (splitsplit.{u_1} {α : Type u_1} (a✝ : List α) : List α × List α ysList α).snd = Eq.{u_1} {α : Sort u_1} (a✝a✝¹ : α) : PropThe equality relation. It has one introduction rule, `Eq.refl`. We use `a = b` as notation for `Eq a b`. A fundamental property of equality is that it is an equivalence relation. ``` variable (α : Type) (a b c d : α) variable (hab : a = b) (hcb : c = b) (hcd : c = d) example : a = d := Eq.trans (Eq.trans hab (Eq.symm hcb)) hcd ``` Equality is much more than an equivalence relation, however. It has the important property that every assertion respects the equivalence, in the sense that we can substitute equal expressions without changing the truth value. That is, given `h1 : a = b` and `h2 : p a`, we can construct a proof for `p b` using substitution: `Eq.subst h1 h2`. Example: ``` example (α : Type) (a b : α) (p : α → Prop) (h1 : a = b) (h2 : p a) : p b := Eq.subst h1 h2 example (α : Type) (a b : α) (p : α → Prop) (h1 : a = b) (h2 : p a) : p b := h1 ▸ h2 ``` The triangle in the second presentation is a macro built on top of `Eq.subst` and `Eq.symm`, and you can enter it by typing `\t`. For more information: [Equality](https://lean-lang.org/theorem_proving_in_lean4/quantifiers_and_equality.html#equality) List.lengthList.length.{u_1} {α : Type u_1} (a✝ : List α) : NatThe length of a list: `[].length = 0` and `(a :: l).length = l.length + 1`. This function is overridden in the compiler to `lengthTR`, which uses constant stack space, while leaving this function to use the "naive" recursion which is easier for reasoning. ysList α
List.lengthList.length.{u_1} {α : Type u_1} (a✝ : List α) : NatThe length of a list: `[].length = 0` and `(a :: l).length = l.length + 1`. This function is overridden in the compiler to `lengthTR`, which uses constant stack space, while leaving this function to use the "naive" recursion which is easier for reasoning. (splitsplit.{u_1} {α : Type u_1} (a✝ : List α) : List α × List α (yα :: List.cons.{u} {α : Type u} (head : α) (tail : List α) : List αIf `a : α` and `l : List α`, then `cons a l`, or `a :: l`, is the list whose first element is `a` and with `l` as the rest of the list. y'α :: List.cons.{u} {α : Type u} (head : α) (tail : List α) : List αIf `a : α` and `l : List α`, then `cons a l`, or `a :: l`, is the list whose first element is `a` and with `l` as the rest of the list. ysList α)).fst + HAdd.hAdd.{u, v, w} {α : Type u} {β : Type v} {γ : outParam (Type w)} [self : HAdd α β γ] (a✝ : α) (a✝¹ : β) : γ`a + b` computes the sum of `a` and `b`. The meaning of this notation is type-dependent. List.lengthList.length.{u_1} {α : Type u_1} (a✝ : List α) : NatThe length of a list: `[].length = 0` and `(a :: l).length = l.length + 1`. This function is overridden in the compiler to `lengthTR`, which uses constant stack space, while leaving this function to use the "naive" recursion which is easier for reasoning. (splitsplit.{u_1} {α : Type u_1} (a✝ : List α) : List α × List α (yα :: List.cons.{u} {α : Type u} (head : α) (tail : List α) : List αIf `a : α` and `l : List α`, then `cons a l`, or `a :: l`, is the list whose first element is `a` and with `l` as the rest of the list. y'α :: List.cons.{u} {α : Type u} (head : α) (tail : List α) : List αIf `a : α` and `l : List α`, then `cons a l`, or `a :: l`, is the list whose first element is `a` and with `l` as the rest of the list. ysList α)).snd = Eq.{u_1} {α : Sort u_1} (a✝a✝¹ : α) : PropThe equality relation. It has one introduction rule, `Eq.refl`. We use `a = b` as notation for `Eq a b`. A fundamental property of equality is that it is an equivalence relation. ``` variable (α : Type) (a b c d : α) variable (hab : a = b) (hcb : c = b) (hcd : c = d) example : a = d := Eq.trans (Eq.trans hab (Eq.symm hcb)) hcd ``` Equality is much more than an equivalence relation, however. It has the important property that every assertion respects the equivalence, in the sense that we can substitute equal expressions without changing the truth value. That is, given `h1 : a = b` and `h2 : p a`, we can construct a proof for `p b` using substitution: `Eq.subst h1 h2`. Example: ``` example (α : Type) (a b : α) (p : α → Prop) (h1 : a = b) (h2 : p a) : p b := Eq.subst h1 h2 example (α : Type) (a b : α) (p : α → Prop) (h1 : a = b) (h2 : p a) : p b := h1 ▸ h2 ``` The triangle in the second presentation is a macro built on top of `Eq.subst` and `Eq.symm`, and you can enter it by typing `\t`. For more information: [Equality](https://lean-lang.org/theorem_proving_in_lean4/quantifiers_and_equality.html#equality) List.lengthList.length.{u_1} {α : Type u_1} (a✝ : List α) : NatThe length of a list: `[].length = 0` and `(a :: l).length = l.length + 1`. This function is overridden in the compiler to `lengthTR`, which uses constant stack space, while leaving this function to use the "naive" recursion which is easier for reasoning. (yα :: List.cons.{u} {α : Type u} (head : α) (tail : List α) : List αIf `a : α` and `l : List α`, then `cons a l`, or `a :: l`, is the list whose first element is `a` and with `l` as the rest of the list. y'α :: List.cons.{u} {α : Type u} (head : α) (tail : List α) : List αIf `a : α` and `l : List α`, then `cons a l`, or `a :: l`, is the list whose first element is `a` and with `l` as the rest of the list. ysList α)
αType u_1:Type u_1
xsList α:ListList.{u} (α : Type u) : Type u`List α` is the type of ordered lists with elements of type `α`. It is implemented as a linked list. `List α` is isomorphic to `Array α`, but they are useful for different things: * `List α` is easier for reasoning, and `Array α` is modeled as a wrapper around `List α` * `List α` works well as a persistent data structure, when many copies of the tail are shared. When the value is not shared, `Array α` will have better performance because it can do destructive updates. αType u_1
yα:αType u_1
y'α:αType u_1
ysList α:ListList.{u} (α : Type u) : Type u`List α` is the type of ordered lists with elements of type `α`. It is implemented as a linked list. `List α` is isomorphic to `Array α`, but they are useful for different things: * `List α` is easier for reasoning, and `Array α` is modeled as a wrapper around `List α` * `List α` works well as a persistent data structure, when many copies of the tail are shared. When the value is not shared, `Array α` will have better performance because it can do destructive updates. αType u_1
thisList.length (split ys).fst + List.length (split ys).snd = List.length ys:List.lengthList.length.{u_1} {α : Type u_1} (a✝ : List α) : NatThe length of a list: `[].length = 0` and `(a :: l).length = l.length + 1`. This function is overridden in the compiler to `lengthTR`, which uses constant stack space, while leaving this function to use the "naive" recursion which is easier for reasoning. (splitsplit.{u_1} {α : Type u_1} (a✝ : List α) : List α × List α ysList α).fst + HAdd.hAdd.{u, v, w} {α : Type u} {β : Type v} {γ : outParam (Type w)} [self : HAdd α β γ] (a✝ : α) (a✝¹ : β) : γ`a + b` computes the sum of `a` and `b`. The meaning of this notation is type-dependent. List.lengthList.length.{u_1} {α : Type u_1} (a✝ : List α) : NatThe length of a list: `[].length = 0` and `(a :: l).length = l.length + 1`. This function is overridden in the compiler to `lengthTR`, which uses constant stack space, while leaving this function to use the "naive" recursion which is easier for reasoning. (splitsplit.{u_1} {α : Type u_1} (a✝ : List α) : List α × List α ysList α).snd = Eq.{u_1} {α : Sort u_1} (a✝a✝¹ : α) : PropThe equality relation. It has one introduction rule, `Eq.refl`. We use `a = b` as notation for `Eq a b`. A fundamental property of equality is that it is an equivalence relation. ``` variable (α : Type) (a b c d : α) variable (hab : a = b) (hcb : c = b) (hcd : c = d) example : a = d := Eq.trans (Eq.trans hab (Eq.symm hcb)) hcd ``` Equality is much more than an equivalence relation, however. It has the important property that every assertion respects the equivalence, in the sense that we can substitute equal expressions without changing the truth value. That is, given `h1 : a = b` and `h2 : p a`, we can construct a proof for `p b` using substitution: `Eq.subst h1 h2`. Example: ``` example (α : Type) (a b : α) (p : α → Prop) (h1 : a = b) (h2 : p a) : p b := Eq.subst h1 h2 example (α : Type) (a b : α) (p : α → Prop) (h1 : a = b) (h2 : p a) : p b := h1 ▸ h2 ``` The triangle in the second presentation is a macro built on top of `Eq.subst` and `Eq.symm`, and you can enter it by typing `\t`. For more information: [Equality](https://lean-lang.org/theorem_proving_in_lean4/quantifiers_and_equality.html#equality) List.lengthList.length.{u_1} {α : Type u_1} (a✝ : List α) : NatThe length of a list: `[].length = 0` and `(a :: l).length = l.length + 1`. This function is overridden in the compiler to `lengthTR`, which uses constant stack space, while leaving this function to use the "naive" recursion which is easier for reasoning. ysList α
List.lengthList.length.{u_1} {α : Type u_1} (a✝ : List α) : NatThe length of a list: `[].length = 0` and `(a :: l).length = l.length + 1`. This function is overridden in the compiler to `lengthTR`, which uses constant stack space, while leaving this function to use the "naive" recursion which is easier for reasoning. (splitsplit.{u_1} {α : Type u_1} (a✝ : List α) : List α × List α ysList α).fst + HAdd.hAdd.{u, v, w} {α : Type u} {β : Type v} {γ : outParam (Type w)} [self : HAdd α β γ] (a✝ : α) (a✝¹ : β) : γ`a + b` computes the sum of `a` and `b`. The meaning of this notation is type-dependent. 1 + HAdd.hAdd.{u, v, w} {α : Type u} {β : Type v} {γ : outParam (Type w)} [self : HAdd α β γ] (a✝ : α) (a✝¹ : β) : γ`a + b` computes the sum of `a` and `b`. The meaning of this notation is type-dependent. List.lengthList.length.{u_1} {α : Type u_1} (a✝ : List α) : NatThe length of a list: `[].length = 0` and `(a :: l).length = l.length + 1`. This function is overridden in the compiler to `lengthTR`, which uses constant stack space, while leaving this function to use the "naive" recursion which is easier for reasoning. (splitsplit.{u_1} {α : Type u_1} (a✝ : List α) : List α × List α ysList α).snd + HAdd.hAdd.{u, v, w} {α : Type u} {β : Type v} {γ : outParam (Type w)} [self : HAdd α β γ] (a✝ : α) (a✝¹ : β) : γ`a + b` computes the sum of `a` and `b`. The meaning of this notation is type-dependent. 1 = Eq.{u_1} {α : Sort u_1} (a✝a✝¹ : α) : PropThe equality relation. It has one introduction rule, `Eq.refl`. We use `a = b` as notation for `Eq a b`. A fundamental property of equality is that it is an equivalence relation. ``` variable (α : Type) (a b c d : α) variable (hab : a = b) (hcb : c = b) (hcd : c = d) example : a = d := Eq.trans (Eq.trans hab (Eq.symm hcb)) hcd ``` Equality is much more than an equivalence relation, however. It has the important property that every assertion respects the equivalence, in the sense that we can substitute equal expressions without changing the truth value. That is, given `h1 : a = b` and `h2 : p a`, we can construct a proof for `p b` using substitution: `Eq.subst h1 h2`. Example: ``` example (α : Type) (a b : α) (p : α → Prop) (h1 : a = b) (h2 : p a) : p b := Eq.subst h1 h2 example (α : Type) (a b : α) (p : α → Prop) (h1 : a = b) (h2 : p a) : p b := h1 ▸ h2 ``` The triangle in the second presentation is a macro built on top of `Eq.subst` and `Eq.symm`, and you can enter it by typing `\t`. For more information: [Equality](https://lean-lang.org/theorem_proving_in_lean4/quantifiers_and_equality.html#equality) List.lengthList.length.{u_1} {α : Type u_1} (a✝ : List α) : NatThe length of a list: `[].length = 0` and `(a :: l).length = l.length + 1`. This function is overridden in the compiler to `lengthTR`, which uses constant stack space, while leaving this function to use the "naive" recursion which is easier for reasoning. ysList α + HAdd.hAdd.{u, v, w} {α : Type u} {β : Type v} {γ : outParam (Type w)} [self : HAdd α β γ] (a✝ : α) (a✝¹ : β) : γ`a + b` computes the sum of `a` and `b`. The meaning of this notation is type-dependent. 2
unsolved goals
α : Type u_1
xs : List α
y y' : α
ys : List α
this : List.length (split ys).fst + List.length (split ys).snd = List.length ys
⊢ List.length (split ys).fst + 1 + List.length (split ys).snd + 1 = List.length ys + 2

The change tactic also optionally accepts a hypothesis name using the same at syntax as simp and rw, causing it to rewrite the hypothesis.

Closing Tactics

solve_by_elim

The solve_by_elim tactic performs a proof search, using the apply tactic on the assumptions in scope along with an optional list of provided lemmas repeatedly to close the current goal. Unlike apply, solve_by_elim will also use the assumptions or lemmas in nested positions, automatically combining them with congrArgcongrArg.{u, v} {α : Sort u} {β : Sort v} {a₁ a₂ : α} (f : α → β) (h : a₁ = a₂) : f a₁ = f a₂Congruence in the function argument: if `a₁ = a₂` then `f a₁ = f a₂` for any (nondependent) function `f`. This is more powerful than it might look at first, because you can also use a lambda expression for `f` to prove that `<something containing a₁> = <something containing a₂>`. This function is used internally by tactics like `congr` and `simp` to apply equalities inside subterms. For more information: [Equality](https://lean-lang.org/theorem_proving_in_lean4/quantifiers_and_equality.html#equality) and congrFuncongrFun.{u, v} {α : Sort u} {β : α → Sort v} {f g : (x : α) → β x} (h : f = g) (a : α) : f a = g aCongruence in the function part of an application: If `f = g` then `f a = g a`. as needed.

In this updated version of the proof that every natural number is even or odd, solve_by_elim automatically uses the proofs in the local context to find the existential witness and prove the desired property:

theorem even_or_odd_root_.even_or_odd (n : Nat) : (∃ half, n = 2 * half) ∨ ∃ half, n = 2 * half + 1 (nNat : NatNat : TypeThe type of natural numbers, starting at zero. It is defined as an inductive type freely generated by "zero is a natural number" and "the successor of a natural number is a natural number". You can prove a theorem `P n` about `n : Nat` by `induction n`, which will expect a proof of the theorem for `P 0`, and a proof of `P (succ i)` assuming a proof of `P i`. The same method also works to define functions by recursion on natural numbers: induction and recursion are two expressions of the same operation from Lean's point of view. ``` open Nat example (n : Nat) : n < succ n := by induction n with | zero => show 0 < 1 decide | succ i ih => -- ih : i < succ i show succ i < succ (succ i) exact Nat.succ_lt_succ ih ``` This type is special-cased by both the kernel and the compiler: * The type of expressions contains "`Nat` literals" as a primitive constructor, and the kernel knows how to reduce zero/succ expressions to nat literals. * If implemented naively, this type would represent a numeral `n` in unary as a linked list with `n` links, which is horribly inefficient. Instead, the runtime itself has a special representation for `Nat` which stores numbers up to 2^63 directly and larger numbers use an arbitrary precision "bignum" library (usually [GMP](https://gmplib.org/)). ) : ( halfNat, nNat = 2 * halfNat) ( halfNat, nNat = 2 * halfNat + 1) :=
nNat:NatNat : TypeThe type of natural numbers, starting at zero. It is defined as an inductive type freely generated by "zero is a natural number" and "the successor of a natural number is a natural number". You can prove a theorem `P n` about `n : Nat` by `induction n`, which will expect a proof of the theorem for `P 0`, and a proof of `P (succ i)` assuming a proof of `P i`. The same method also works to define functions by recursion on natural numbers: induction and recursion are two expressions of the same operation from Lean's point of view. ``` open Nat example (n : Nat) : n < succ n := by induction n with | zero => show 0 < 1 decide | succ i ih => -- ih : i < succ i show succ i < succ (succ i) exact Nat.succ_lt_succ ih ``` This type is special-cased by both the kernel and the compiler: * The type of expressions contains "`Nat` literals" as a primitive constructor, and the kernel knows how to reduce zero/succ expressions to nat literals. * If implemented naively, this type would represent a numeral `n` in unary as a linked list with `n` links, which is horribly inefficient. Instead, the runtime itself has a special representation for `Nat` which stores numbers up to 2^63 directly and larger numbers use an arbitrary precision "bignum" library (usually [GMP](https://gmplib.org/)).
(∃ half, nNat = Eq.{u_1} {α : Sort u_1} (a✝a✝¹ : α) : PropThe equality relation. It has one introduction rule, `Eq.refl`. We use `a = b` as notation for `Eq a b`. A fundamental property of equality is that it is an equivalence relation. ``` variable (α : Type) (a b c d : α) variable (hab : a = b) (hcb : c = b) (hcd : c = d) example : a = d := Eq.trans (Eq.trans hab (Eq.symm hcb)) hcd ``` Equality is much more than an equivalence relation, however. It has the important property that every assertion respects the equivalence, in the sense that we can substitute equal expressions without changing the truth value. That is, given `h1 : a = b` and `h2 : p a`, we can construct a proof for `p b` using substitution: `Eq.subst h1 h2`. Example: ``` example (α : Type) (a b : α) (p : α → Prop) (h1 : a = b) (h2 : p a) : p b := Eq.subst h1 h2 example (α : Type) (a b : α) (p : α → Prop) (h1 : a = b) (h2 : p a) : p b := h1 ▸ h2 ``` The triangle in the second presentation is a macro built on top of `Eq.subst` and `Eq.symm`, and you can enter it by typing `\t`. For more information: [Equality](https://lean-lang.org/theorem_proving_in_lean4/quantifiers_and_equality.html#equality) 2 * HMul.hMul.{u, v, w} {α : Type u} {β : Type v} {γ : outParam (Type w)} [self : HMul α β γ] (a✝ : α) (a✝¹ : β) : γ`a * b` computes the product of `a` and `b`. The meaning of this notation is type-dependent. halfNat)Or (a b : Prop) : Prop`Or a b`, or `a ∨ b`, is the disjunction of propositions. There are two constructors for `Or`, called `Or.inl : a → a ∨ b` and `Or.inr : b → a ∨ b`, and you can use `match` or `cases` to destruct an `Or` assumption into the two cases. ∃ half, nNat = Eq.{u_1} {α : Sort u_1} (a✝a✝¹ : α) : PropThe equality relation. It has one introduction rule, `Eq.refl`. We use `a = b` as notation for `Eq a b`. A fundamental property of equality is that it is an equivalence relation. ``` variable (α : Type) (a b c d : α) variable (hab : a = b) (hcb : c = b) (hcd : c = d) example : a = d := Eq.trans (Eq.trans hab (Eq.symm hcb)) hcd ``` Equality is much more than an equivalence relation, however. It has the important property that every assertion respects the equivalence, in the sense that we can substitute equal expressions without changing the truth value. That is, given `h1 : a = b` and `h2 : p a`, we can construct a proof for `p b` using substitution: `Eq.subst h1 h2`. Example: ``` example (α : Type) (a b : α) (p : α → Prop) (h1 : a = b) (h2 : p a) : p b := Eq.subst h1 h2 example (α : Type) (a b : α) (p : α → Prop) (h1 : a = b) (h2 : p a) : p b := h1 ▸ h2 ``` The triangle in the second presentation is a macro built on top of `Eq.subst` and `Eq.symm`, and you can enter it by typing `\t`. For more information: [Equality](https://lean-lang.org/theorem_proving_in_lean4/quantifiers_and_equality.html#equality) 2 * HMul.hMul.{u, v, w} {α : Type u} {β : Type v} {γ : outParam (Type w)} [self : HMul α β γ] (a✝ : α) (a✝¹ : β) : γ`a * b` computes the product of `a` and `b`. The meaning of this notation is type-dependent. halfNat + HAdd.hAdd.{u, v, w} {α : Type u} {β : Type v} {γ : outParam (Type w)} [self : HAdd α β γ] (a✝ : α) (a✝¹ : β) : γ`a + b` computes the sum of `a` and `b`. The meaning of this notation is type-dependent. 1
inductionAssuming `x` is a variable in the local context with an inductive type, `induction x` applies induction on `x` to the main goal, producing one goal for each constructor of the inductive type, in which the target is replaced by a general instance of that constructor and an inductive hypothesis is added for each recursive argument to the constructor. If the type of an element in the local context depends on `x`, that element is reverted and reintroduced afterward, so that the inductive hypothesis incorporates that hypothesis as well. For example, given `n : Nat` and a goal with a hypothesis `h : P n` and target `Q n`, `induction n` produces one goal with hypothesis `h : P 0` and target `Q 0`, and one goal with hypotheses `h : P (Nat.succ a)` and `ih₁ : P a → Q a` and target `Q (Nat.succ a)`. Here the names `a` and `ih₁` are chosen automatically and are not accessible. You can use `with` to provide the variables names for each constructor. - `induction e`, where `e` is an expression instead of a variable, generalizes `e` in the goal, and then performs induction on the resulting variable. - `induction e using r` allows the user to specify the principle of induction that should be used. Here `r` should be a term whose result type must be of the form `C t`, where `C` is a bound variable and `t` is a (possibly empty) sequence of bound variables - `induction e generalizing z₁ ... zₙ`, where `z₁ ... zₙ` are variables in the local context, generalizes over `z₁ ... zₙ` before applying the induction but then introduces them in each goal. In other words, the net effect is that each inductive hypothesis is generalized. - Given `x : Nat`, `induction x with | zero => tac₁ | succ x' ih => tac₂` uses tactic `tac₁` for the `zero` case, and `tac₂` for the `succ` case. nNat withAfter `with`, there is an optional tactic that runs on all branches, and then a list of alternatives. | zeroNat.zero : Nat`Nat.zero`, normally written `0 : Nat`, is the smallest natural number. This is one of the two constructors of `Nat`.
zero(∃ half, Nat.zeroNat.zero : Nat`Nat.zero`, normally written `0 : Nat`, is the smallest natural number. This is one of the two constructors of `Nat`. = Eq.{u_1} {α : Sort u_1} (a✝a✝¹ : α) : PropThe equality relation. It has one introduction rule, `Eq.refl`. We use `a = b` as notation for `Eq a b`. A fundamental property of equality is that it is an equivalence relation. ``` variable (α : Type) (a b c d : α) variable (hab : a = b) (hcb : c = b) (hcd : c = d) example : a = d := Eq.trans (Eq.trans hab (Eq.symm hcb)) hcd ``` Equality is much more than an equivalence relation, however. It has the important property that every assertion respects the equivalence, in the sense that we can substitute equal expressions without changing the truth value. That is, given `h1 : a = b` and `h2 : p a`, we can construct a proof for `p b` using substitution: `Eq.subst h1 h2`. Example: ``` example (α : Type) (a b : α) (p : α → Prop) (h1 : a = b) (h2 : p a) : p b := Eq.subst h1 h2 example (α : Type) (a b : α) (p : α → Prop) (h1 : a = b) (h2 : p a) : p b := h1 ▸ h2 ``` The triangle in the second presentation is a macro built on top of `Eq.subst` and `Eq.symm`, and you can enter it by typing `\t`. For more information: [Equality](https://lean-lang.org/theorem_proving_in_lean4/quantifiers_and_equality.html#equality) 2 * HMul.hMul.{u, v, w} {α : Type u} {β : Type v} {γ : outParam (Type w)} [self : HMul α β γ] (a✝ : α) (a✝¹ : β) : γ`a * b` computes the product of `a` and `b`. The meaning of this notation is type-dependent. halfNat)Or (a b : Prop) : Prop`Or a b`, or `a ∨ b`, is the disjunction of propositions. There are two constructors for `Or`, called `Or.inl : a → a ∨ b` and `Or.inr : b → a ∨ b`, and you can use `match` or `cases` to destruct an `Or` assumption into the two cases. ∃ half, Nat.zeroNat.zero : Nat`Nat.zero`, normally written `0 : Nat`, is the smallest natural number. This is one of the two constructors of `Nat`. = Eq.{u_1} {α : Sort u_1} (a✝a✝¹ : α) : PropThe equality relation. It has one introduction rule, `Eq.refl`. We use `a = b` as notation for `Eq a b`. A fundamental property of equality is that it is an equivalence relation. ``` variable (α : Type) (a b c d : α) variable (hab : a = b) (hcb : c = b) (hcd : c = d) example : a = d := Eq.trans (Eq.trans hab (Eq.symm hcb)) hcd ``` Equality is much more than an equivalence relation, however. It has the important property that every assertion respects the equivalence, in the sense that we can substitute equal expressions without changing the truth value. That is, given `h1 : a = b` and `h2 : p a`, we can construct a proof for `p b` using substitution: `Eq.subst h1 h2`. Example: ``` example (α : Type) (a b : α) (p : α → Prop) (h1 : a = b) (h2 : p a) : p b := Eq.subst h1 h2 example (α : Type) (a b : α) (p : α → Prop) (h1 : a = b) (h2 : p a) : p b := h1 ▸ h2 ``` The triangle in the second presentation is a macro built on top of `Eq.subst` and `Eq.symm`, and you can enter it by typing `\t`. For more information: [Equality](https://lean-lang.org/theorem_proving_in_lean4/quantifiers_and_equality.html#equality) 2 * HMul.hMul.{u, v, w} {α : Type u} {β : Type v} {γ : outParam (Type w)} [self : HMul α β γ] (a✝ : α) (a✝¹ : β) : γ`a * b` computes the product of `a` and `b`. The meaning of this notation is type-dependent. halfNat + HAdd.hAdd.{u, v, w} {α : Type u} {β : Type v} {γ : outParam (Type w)} [self : HAdd α β γ] (a✝ : α) (a✝¹ : β) : γ`a + b` computes the sum of `a` and `b`. The meaning of this notation is type-dependent. 1
zero.h∃ half, Nat.zeroNat.zero : Nat`Nat.zero`, normally written `0 : Nat`, is the smallest natural number. This is one of the two constructors of `Nat`. = Eq.{u_1} {α : Sort u_1} (a✝a✝¹ : α) : PropThe equality relation. It has one introduction rule, `Eq.refl`. We use `a = b` as notation for `Eq a b`. A fundamental property of equality is that it is an equivalence relation. ``` variable (α : Type) (a b c d : α) variable (hab : a = b) (hcb : c = b) (hcd : c = d) example : a = d := Eq.trans (Eq.trans hab (Eq.symm hcb)) hcd ``` Equality is much more than an equivalence relation, however. It has the important property that every assertion respects the equivalence, in the sense that we can substitute equal expressions without changing the truth value. That is, given `h1 : a = b` and `h2 : p a`, we can construct a proof for `p b` using substitution: `Eq.subst h1 h2`. Example: ``` example (α : Type) (a b : α) (p : α → Prop) (h1 : a = b) (h2 : p a) : p b := Eq.subst h1 h2 example (α : Type) (a b : α) (p : α → Prop) (h1 : a = b) (h2 : p a) : p b := h1 ▸ h2 ``` The triangle in the second presentation is a macro built on top of `Eq.subst` and `Eq.symm`, and you can enter it by typing `\t`. For more information: [Equality](https://lean-lang.org/theorem_proving_in_lean4/quantifiers_and_equality.html#equality) 2 * HMul.hMul.{u, v, w} {α : Type u} {β : Type v} {γ : outParam (Type w)} [self : HMul α β γ] (a✝ : α) (a✝¹ : β) : γ`a * b` computes the product of `a` and `b`. The meaning of this notation is type-dependent. halfNat
;
All goals completed! 🐙
| succNat.succ (n : Nat) : NatThe successor function on natural numbers, `succ n = n + 1`. This is one of the two constructors of `Nat`. n'Nat ih(∃ half, n' = 2 * half) ∨ ∃ half, n' = 2 * half + 1
succ
n'Nat:NatNat : TypeThe type of natural numbers, starting at zero. It is defined as an inductive type freely generated by "zero is a natural number" and "the successor of a natural number is a natural number". You can prove a theorem `P n` about `n : Nat` by `induction n`, which will expect a proof of the theorem for `P 0`, and a proof of `P (succ i)` assuming a proof of `P i`. The same method also works to define functions by recursion on natural numbers: induction and recursion are two expressions of the same operation from Lean's point of view. ``` open Nat example (n : Nat) : n < succ n := by induction n with | zero => show 0 < 1 decide | succ i ih => -- ih : i < succ i show succ i < succ (succ i) exact Nat.succ_lt_succ ih ``` This type is special-cased by both the kernel and the compiler: * The type of expressions contains "`Nat` literals" as a primitive constructor, and the kernel knows how to reduce zero/succ expressions to nat literals. * If implemented naively, this type would represent a numeral `n` in unary as a linked list with `n` links, which is horribly inefficient. Instead, the runtime itself has a special representation for `Nat` which stores numbers up to 2^63 directly and larger numbers use an arbitrary precision "bignum" library (usually [GMP](https://gmplib.org/)).
ih(∃ half, n' = 2 * half) ∨ ∃ half, n' = 2 * half + 1:(∃ half, n'Nat = Eq.{u_1} {α : Sort u_1} (a✝a✝¹ : α) : PropThe equality relation. It has one introduction rule, `Eq.refl`. We use `a = b` as notation for `Eq a b`. A fundamental property of equality is that it is an equivalence relation. ``` variable (α : Type) (a b c d : α) variable (hab : a = b) (hcb : c = b) (hcd : c = d) example : a = d := Eq.trans (Eq.trans hab (Eq.symm hcb)) hcd ``` Equality is much more than an equivalence relation, however. It has the important property that every assertion respects the equivalence, in the sense that we can substitute equal expressions without changing the truth value. That is, given `h1 : a = b` and `h2 : p a`, we can construct a proof for `p b` using substitution: `Eq.subst h1 h2`. Example: ``` example (α : Type) (a b : α) (p : α → Prop) (h1 : a = b) (h2 : p a) : p b := Eq.subst h1 h2 example (α : Type) (a b : α) (p : α → Prop) (h1 : a = b) (h2 : p a) : p b := h1 ▸ h2 ``` The triangle in the second presentation is a macro built on top of `Eq.subst` and `Eq.symm`, and you can enter it by typing `\t`. For more information: [Equality](https://lean-lang.org/theorem_proving_in_lean4/quantifiers_and_equality.html#equality) 2 * HMul.hMul.{u, v, w} {α : Type u} {β : Type v} {γ : outParam (Type w)} [self : HMul α β γ] (a✝ : α) (a✝¹ : β) : γ`a * b` computes the product of `a` and `b`. The meaning of this notation is type-dependent. halfNat)Or (a b : Prop) : Prop`Or a b`, or `a ∨ b`, is the disjunction of propositions. There are two constructors for `Or`, called `Or.inl : a → a ∨ b` and `Or.inr : b → a ∨ b`, and you can use `match` or `cases` to destruct an `Or` assumption into the two cases. ∃ half, n'Nat = Eq.{u_1} {α : Sort u_1} (a✝a✝¹ : α) : PropThe equality relation. It has one introduction rule, `Eq.refl`. We use `a = b` as notation for `Eq a b`. A fundamental property of equality is that it is an equivalence relation. ``` variable (α : Type) (a b c d : α) variable (hab : a = b) (hcb : c = b) (hcd : c = d) example : a = d := Eq.trans (Eq.trans hab (Eq.symm hcb)) hcd ``` Equality is much more than an equivalence relation, however. It has the important property that every assertion respects the equivalence, in the sense that we can substitute equal expressions without changing the truth value. That is, given `h1 : a = b` and `h2 : p a`, we can construct a proof for `p b` using substitution: `Eq.subst h1 h2`. Example: ``` example (α : Type) (a b : α) (p : α → Prop) (h1 : a = b) (h2 : p a) : p b := Eq.subst h1 h2 example (α : Type) (a b : α) (p : α → Prop) (h1 : a = b) (h2 : p a) : p b := h1 ▸ h2 ``` The triangle in the second presentation is a macro built on top of `Eq.subst` and `Eq.symm`, and you can enter it by typing `\t`. For more information: [Equality](https://lean-lang.org/theorem_proving_in_lean4/quantifiers_and_equality.html#equality) 2 * HMul.hMul.{u, v, w} {α : Type u} {β : Type v} {γ : outParam (Type w)} [self : HMul α β γ] (a✝ : α) (a✝¹ : β) : γ`a * b` computes the product of `a` and `b`. The meaning of this notation is type-dependent. halfNat + HAdd.hAdd.{u, v, w} {α : Type u} {β : Type v} {γ : outParam (Type w)} [self : HAdd α β γ] (a✝ : α) (a✝¹ : β) : γ`a + b` computes the sum of `a` and `b`. The meaning of this notation is type-dependent. 1
(∃ half, Nat.succNat.succ (n : Nat) : NatThe successor function on natural numbers, `succ n = n + 1`. This is one of the two constructors of `Nat`. n'Nat = Eq.{u_1} {α : Sort u_1} (a✝a✝¹ : α) : PropThe equality relation. It has one introduction rule, `Eq.refl`. We use `a = b` as notation for `Eq a b`. A fundamental property of equality is that it is an equivalence relation. ``` variable (α : Type) (a b c d : α) variable (hab : a = b) (hcb : c = b) (hcd : c = d) example : a = d := Eq.trans (Eq.trans hab (Eq.symm hcb)) hcd ``` Equality is much more than an equivalence relation, however. It has the important property that every assertion respects the equivalence, in the sense that we can substitute equal expressions without changing the truth value. That is, given `h1 : a = b` and `h2 : p a`, we can construct a proof for `p b` using substitution: `Eq.subst h1 h2`. Example: ``` example (α : Type) (a b : α) (p : α → Prop) (h1 : a = b) (h2 : p a) : p b := Eq.subst h1 h2 example (α : Type) (a b : α) (p : α → Prop) (h1 : a = b) (h2 : p a) : p b := h1 ▸ h2 ``` The triangle in the second presentation is a macro built on top of `Eq.subst` and `Eq.symm`, and you can enter it by typing `\t`. For more information: [Equality](https://lean-lang.org/theorem_proving_in_lean4/quantifiers_and_equality.html#equality) 2 * HMul.hMul.{u, v, w} {α : Type u} {β : Type v} {γ : outParam (Type w)} [self : HMul α β γ] (a✝ : α) (a✝¹ : β) : γ`a * b` computes the product of `a` and `b`. The meaning of this notation is type-dependent. halfNat)Or (a b : Prop) : Prop`Or a b`, or `a ∨ b`, is the disjunction of propositions. There are two constructors for `Or`, called `Or.inl : a → a ∨ b` and `Or.inr : b → a ∨ b`, and you can use `match` or `cases` to destruct an `Or` assumption into the two cases. ∃ half, Nat.succNat.succ (n : Nat) : NatThe successor function on natural numbers, `succ n = n + 1`. This is one of the two constructors of `Nat`. n'Nat = Eq.{u_1} {α : Sort u_1} (a✝a✝¹ : α) : PropThe equality relation. It has one introduction rule, `Eq.refl`. We use `a = b` as notation for `Eq a b`. A fundamental property of equality is that it is an equivalence relation. ``` variable (α : Type) (a b c d : α) variable (hab : a = b) (hcb : c = b) (hcd : c = d) example : a = d := Eq.trans (Eq.trans hab (Eq.symm hcb)) hcd ``` Equality is much more than an equivalence relation, however. It has the important property that every assertion respects the equivalence, in the sense that we can substitute equal expressions without changing the truth value. That is, given `h1 : a = b` and `h2 : p a`, we can construct a proof for `p b` using substitution: `Eq.subst h1 h2`. Example: ``` example (α : Type) (a b : α) (p : α → Prop) (h1 : a = b) (h2 : p a) : p b := Eq.subst h1 h2 example (α : Type) (a b : α) (p : α → Prop) (h1 : a = b) (h2 : p a) : p b := h1 ▸ h2 ``` The triangle in the second presentation is a macro built on top of `Eq.subst` and `Eq.symm`, and you can enter it by typing `\t`. For more information: [Equality](https://lean-lang.org/theorem_proving_in_lean4/quantifiers_and_equality.html#equality) 2 * HMul.hMul.{u, v, w} {α : Type u} {β : Type v} {γ : outParam (Type w)} [self : HMul α β γ] (a✝ : α) (a✝¹ : β) : γ`a * b` computes the product of `a` and `b`. The meaning of this notation is type-dependent. halfNat + HAdd.hAdd.{u, v, w} {α : Type u} {β : Type v} {γ : outParam (Type w)} [self : HAdd α β γ] (a✝ : α) (a✝¹ : β) : γ`a + b` computes the sum of `a` and `b`. The meaning of this notation is type-dependent. 1
succ.inl.intro
n'Nat:NatNat : TypeThe type of natural numbers, starting at zero. It is defined as an inductive type freely generated by "zero is a natural number" and "the successor of a natural number is a natural number". You can prove a theorem `P n` about `n : Nat` by `induction n`, which will expect a proof of the theorem for `P 0`, and a proof of `P (succ i)` assuming a proof of `P i`. The same method also works to define functions by recursion on natural numbers: induction and recursion are two expressions of the same operation from Lean's point of view. ``` open Nat example (n : Nat) : n < succ n := by induction n with | zero => show 0 < 1 decide | succ i ih => -- ih : i < succ i show succ i < succ (succ i) exact Nat.succ_lt_succ ih ``` This type is special-cased by both the kernel and the compiler: * The type of expressions contains "`Nat` literals" as a primitive constructor, and the kernel knows how to reduce zero/succ expressions to nat literals. * If implemented naively, this type would represent a numeral `n` in unary as a linked list with `n` links, which is horribly inefficient. Instead, the runtime itself has a special representation for `Nat` which stores numbers up to 2^63 directly and larger numbers use an arbitrary precision "bignum" library (usually [GMP](https://gmplib.org/)).
halfNat:NatNat : TypeThe type of natural numbers, starting at zero. It is defined as an inductive type freely generated by "zero is a natural number" and "the successor of a natural number is a natural number". You can prove a theorem `P n` about `n : Nat` by `induction n`, which will expect a proof of the theorem for `P 0`, and a proof of `P (succ i)` assuming a proof of `P i`. The same method also works to define functions by recursion on natural numbers: induction and recursion are two expressions of the same operation from Lean's point of view. ``` open Nat example (n : Nat) : n < succ n := by induction n with | zero => show 0 < 1 decide | succ i ih => -- ih : i < succ i show succ i < succ (succ i) exact Nat.succ_lt_succ ih ``` This type is special-cased by both the kernel and the compiler: * The type of expressions contains "`Nat` literals" as a primitive constructor, and the kernel knows how to reduce zero/succ expressions to nat literals. * If implemented naively, this type would represent a numeral `n` in unary as a linked list with `n` links, which is horribly inefficient. Instead, the runtime itself has a special representation for `Nat` which stores numbers up to 2^63 directly and larger numbers use an arbitrary precision "bignum" library (usually [GMP](https://gmplib.org/)).
prfn' = 2 * half:n'Nat = Eq.{u_1} {α : Sort u_1} (a✝a✝¹ : α) : PropThe equality relation. It has one introduction rule, `Eq.refl`. We use `a = b` as notation for `Eq a b`. A fundamental property of equality is that it is an equivalence relation. ``` variable (α : Type) (a b c d : α) variable (hab : a = b) (hcb : c = b) (hcd : c = d) example : a = d := Eq.trans (Eq.trans hab (Eq.symm hcb)) hcd ``` Equality is much more than an equivalence relation, however. It has the important property that every assertion respects the equivalence, in the sense that we can substitute equal expressions without changing the truth value. That is, given `h1 : a = b` and `h2 : p a`, we can construct a proof for `p b` using substitution: `Eq.subst h1 h2`. Example: ``` example (α : Type) (a b : α) (p : α → Prop) (h1 : a = b) (h2 : p a) : p b := Eq.subst h1 h2 example (α : Type) (a b : α) (p : α → Prop) (h1 : a = b) (h2 : p a) : p b := h1 ▸ h2 ``` The triangle in the second presentation is a macro built on top of `Eq.subst` and `Eq.symm`, and you can enter it by typing `\t`. For more information: [Equality](https://lean-lang.org/theorem_proving_in_lean4/quantifiers_and_equality.html#equality) 2 * HMul.hMul.{u, v, w} {α : Type u} {β : Type v} {γ : outParam (Type w)} [self : HMul α β γ] (a✝ : α) (a✝¹ : β) : γ`a * b` computes the product of `a` and `b`. The meaning of this notation is type-dependent. halfNat
(∃ half, Nat.succNat.succ (n : Nat) : NatThe successor function on natural numbers, `succ n = n + 1`. This is one of the two constructors of `Nat`. n'Nat = Eq.{u_1} {α : Sort u_1} (a✝a✝¹ : α) : PropThe equality relation. It has one introduction rule, `Eq.refl`. We use `a = b` as notation for `Eq a b`. A fundamental property of equality is that it is an equivalence relation. ``` variable (α : Type) (a b c d : α) variable (hab : a = b) (hcb : c = b) (hcd : c = d) example : a = d := Eq.trans (Eq.trans hab (Eq.symm hcb)) hcd ``` Equality is much more than an equivalence relation, however. It has the important property that every assertion respects the equivalence, in the sense that we can substitute equal expressions without changing the truth value. That is, given `h1 : a = b` and `h2 : p a`, we can construct a proof for `p b` using substitution: `Eq.subst h1 h2`. Example: ``` example (α : Type) (a b : α) (p : α → Prop) (h1 : a = b) (h2 : p a) : p b := Eq.subst h1 h2 example (α : Type) (a b : α) (p : α → Prop) (h1 : a = b) (h2 : p a) : p b := h1 ▸ h2 ``` The triangle in the second presentation is a macro built on top of `Eq.subst` and `Eq.symm`, and you can enter it by typing `\t`. For more information: [Equality](https://lean-lang.org/theorem_proving_in_lean4/quantifiers_and_equality.html#equality) 2 * HMul.hMul.{u, v, w} {α : Type u} {β : Type v} {γ : outParam (Type w)} [self : HMul α β γ] (a✝ : α) (a✝¹ : β) : γ`a * b` computes the product of `a` and `b`. The meaning of this notation is type-dependent. halfNat)Or (a b : Prop) : Prop`Or a b`, or `a ∨ b`, is the disjunction of propositions. There are two constructors for `Or`, called `Or.inl : a → a ∨ b` and `Or.inr : b → a ∨ b`, and you can use `match` or `cases` to destruct an `Or` assumption into the two cases. ∃ half, Nat.succNat.succ (n : Nat) : NatThe successor function on natural numbers, `succ n = n + 1`. This is one of the two constructors of `Nat`. n'Nat = Eq.{u_1} {α : Sort u_1} (a✝a✝¹ : α) : PropThe equality relation. It has one introduction rule, `Eq.refl`. We use `a = b` as notation for `Eq a b`. A fundamental property of equality is that it is an equivalence relation. ``` variable (α : Type) (a b c d : α) variable (hab : a = b) (hcb : c = b) (hcd : c = d) example : a = d := Eq.trans (Eq.trans hab (Eq.symm hcb)) hcd ``` Equality is much more than an equivalence relation, however. It has the important property that every assertion respects the equivalence, in the sense that we can substitute equal expressions without changing the truth value. That is, given `h1 : a = b` and `h2 : p a`, we can construct a proof for `p b` using substitution: `Eq.subst h1 h2`. Example: ``` example (α : Type) (a b : α) (p : α → Prop) (h1 : a = b) (h2 : p a) : p b := Eq.subst h1 h2 example (α : Type) (a b : α) (p : α → Prop) (h1 : a = b) (h2 : p a) : p b := h1 ▸ h2 ``` The triangle in the second presentation is a macro built on top of `Eq.subst` and `Eq.symm`, and you can enter it by typing `\t`. For more information: [Equality](https://lean-lang.org/theorem_proving_in_lean4/quantifiers_and_equality.html#equality) 2 * HMul.hMul.{u, v, w} {α : Type u} {β : Type v} {γ : outParam (Type w)} [self : HMul α β γ] (a✝ : α) (a✝¹ : β) : γ`a * b` computes the product of `a` and `b`. The meaning of this notation is type-dependent. halfNat + HAdd.hAdd.{u, v, w} {α : Type u} {β : Type v} {γ : outParam (Type w)} [self : HAdd α β γ] (a✝ : α) (a✝¹ : β) : γ`a + b` computes the sum of `a` and `b`. The meaning of this notation is type-dependent. 1
succ.inr.intro
n'Nat:NatNat : TypeThe type of natural numbers, starting at zero. It is defined as an inductive type freely generated by "zero is a natural number" and "the successor of a natural number is a natural number". You can prove a theorem `P n` about `n : Nat` by `induction n`, which will expect a proof of the theorem for `P 0`, and a proof of `P (succ i)` assuming a proof of `P i`. The same method also works to define functions by recursion on natural numbers: induction and recursion are two expressions of the same operation from Lean's point of view. ``` open Nat example (n : Nat) : n < succ n := by induction n with | zero => show 0 < 1 decide | succ i ih => -- ih : i < succ i show succ i < succ (succ i) exact Nat.succ_lt_succ ih ``` This type is special-cased by both the kernel and the compiler: * The type of expressions contains "`Nat` literals" as a primitive constructor, and the kernel knows how to reduce zero/succ expressions to nat literals. * If implemented naively, this type would represent a numeral `n` in unary as a linked list with `n` links, which is horribly inefficient. Instead, the runtime itself has a special representation for `Nat` which stores numbers up to 2^63 directly and larger numbers use an arbitrary precision "bignum" library (usually [GMP](https://gmplib.org/)).
halfNat:NatNat : TypeThe type of natural numbers, starting at zero. It is defined as an inductive type freely generated by "zero is a natural number" and "the successor of a natural number is a natural number". You can prove a theorem `P n` about `n : Nat` by `induction n`, which will expect a proof of the theorem for `P 0`, and a proof of `P (succ i)` assuming a proof of `P i`. The same method also works to define functions by recursion on natural numbers: induction and recursion are two expressions of the same operation from Lean's point of view. ``` open Nat example (n : Nat) : n < succ n := by induction n with | zero => show 0 < 1 decide | succ i ih => -- ih : i < succ i show succ i < succ (succ i) exact Nat.succ_lt_succ ih ``` This type is special-cased by both the kernel and the compiler: * The type of expressions contains "`Nat` literals" as a primitive constructor, and the kernel knows how to reduce zero/succ expressions to nat literals. * If implemented naively, this type would represent a numeral `n` in unary as a linked list with `n` links, which is horribly inefficient. Instead, the runtime itself has a special representation for `Nat` which stores numbers up to 2^63 directly and larger numbers use an arbitrary precision "bignum" library (usually [GMP](https://gmplib.org/)).
prfn' = 2 * half + 1:n'Nat = Eq.{u_1} {α : Sort u_1} (a✝a✝¹ : α) : PropThe equality relation. It has one introduction rule, `Eq.refl`. We use `a = b` as notation for `Eq a b`. A fundamental property of equality is that it is an equivalence relation. ``` variable (α : Type) (a b c d : α) variable (hab : a = b) (hcb : c = b) (hcd : c = d) example : a = d := Eq.trans (Eq.trans hab (Eq.symm hcb)) hcd ``` Equality is much more than an equivalence relation, however. It has the important property that every assertion respects the equivalence, in the sense that we can substitute equal expressions without changing the truth value. That is, given `h1 : a = b` and `h2 : p a`, we can construct a proof for `p b` using substitution: `Eq.subst h1 h2`. Example: ``` example (α : Type) (a b : α) (p : α → Prop) (h1 : a = b) (h2 : p a) : p b := Eq.subst h1 h2 example (α : Type) (a b : α) (p : α → Prop) (h1 : a = b) (h2 : p a) : p b := h1 ▸ h2 ``` The triangle in the second presentation is a macro built on top of `Eq.subst` and `Eq.symm`, and you can enter it by typing `\t`. For more information: [Equality](https://lean-lang.org/theorem_proving_in_lean4/quantifiers_and_equality.html#equality) 2 * HMul.hMul.{u, v, w} {α : Type u} {β : Type v} {γ : outParam (Type w)} [self : HMul α β γ] (a✝ : α) (a✝¹ : β) : γ`a * b` computes the product of `a` and `b`. The meaning of this notation is type-dependent. halfNat + HAdd.hAdd.{u, v, w} {α : Type u} {β : Type v} {γ : outParam (Type w)} [self : HAdd α β γ] (a✝ : α) (a✝¹ : β) : γ`a + b` computes the sum of `a` and `b`. The meaning of this notation is type-dependent. 1
(∃ half, Nat.succNat.succ (n : Nat) : NatThe successor function on natural numbers, `succ n = n + 1`. This is one of the two constructors of `Nat`. n'Nat = Eq.{u_1} {α : Sort u_1} (a✝a✝¹ : α) : PropThe equality relation. It has one introduction rule, `Eq.refl`. We use `a = b` as notation for `Eq a b`. A fundamental property of equality is that it is an equivalence relation. ``` variable (α : Type) (a b c d : α) variable (hab : a = b) (hcb : c = b) (hcd : c = d) example : a = d := Eq.trans (Eq.trans hab (Eq.symm hcb)) hcd ``` Equality is much more than an equivalence relation, however. It has the important property that every assertion respects the equivalence, in the sense that we can substitute equal expressions without changing the truth value. That is, given `h1 : a = b` and `h2 : p a`, we can construct a proof for `p b` using substitution: `Eq.subst h1 h2`. Example: ``` example (α : Type) (a b : α) (p : α → Prop) (h1 : a = b) (h2 : p a) : p b := Eq.subst h1 h2 example (α : Type) (a b : α) (p : α → Prop) (h1 : a = b) (h2 : p a) : p b := h1 ▸ h2 ``` The triangle in the second presentation is a macro built on top of `Eq.subst` and `Eq.symm`, and you can enter it by typing `\t`. For more information: [Equality](https://lean-lang.org/theorem_proving_in_lean4/quantifiers_and_equality.html#equality) 2 * HMul.hMul.{u, v, w} {α : Type u} {β : Type v} {γ : outParam (Type w)} [self : HMul α β γ] (a✝ : α) (a✝¹ : β) : γ`a * b` computes the product of `a` and `b`. The meaning of this notation is type-dependent. halfNat)Or (a b : Prop) : Prop`Or a b`, or `a ∨ b`, is the disjunction of propositions. There are two constructors for `Or`, called `Or.inl : a → a ∨ b` and `Or.inr : b → a ∨ b`, and you can use `match` or `cases` to destruct an `Or` assumption into the two cases. ∃ half, Nat.succNat.succ (n : Nat) : NatThe successor function on natural numbers, `succ n = n + 1`. This is one of the two constructors of `Nat`. n'Nat = Eq.{u_1} {α : Sort u_1} (a✝a✝¹ : α) : PropThe equality relation. It has one introduction rule, `Eq.refl`. We use `a = b` as notation for `Eq a b`. A fundamental property of equality is that it is an equivalence relation. ``` variable (α : Type) (a b c d : α) variable (hab : a = b) (hcb : c = b) (hcd : c = d) example : a = d := Eq.trans (Eq.trans hab (Eq.symm hcb)) hcd ``` Equality is much more than an equivalence relation, however. It has the important property that every assertion respects the equivalence, in the sense that we can substitute equal expressions without changing the truth value. That is, given `h1 : a = b` and `h2 : p a`, we can construct a proof for `p b` using substitution: `Eq.subst h1 h2`. Example: ``` example (α : Type) (a b : α) (p : α → Prop) (h1 : a = b) (h2 : p a) : p b := Eq.subst h1 h2 example (α : Type) (a b : α) (p : α → Prop) (h1 : a = b) (h2 : p a) : p b := h1 ▸ h2 ``` The triangle in the second presentation is a macro built on top of `Eq.subst` and `Eq.symm`, and you can enter it by typing `\t`. For more information: [Equality](https://lean-lang.org/theorem_proving_in_lean4/quantifiers_and_equality.html#equality) 2 * HMul.hMul.{u, v, w} {α : Type u} {β : Type v} {γ : outParam (Type w)} [self : HMul α β γ] (a✝ : α) (a✝¹ : β) : γ`a * b` computes the product of `a` and `b`. The meaning of this notation is type-dependent. halfNat + HAdd.hAdd.{u, v, w} {α : Type u} {β : Type v} {γ : outParam (Type w)} [self : HAdd α β γ] (a✝ : α) (a✝¹ : β) : γ`a + b` computes the sum of `a` and `b`. The meaning of this notation is type-dependent. 1
succ.inl.intro
n'Nat:NatNat : TypeThe type of natural numbers, starting at zero. It is defined as an inductive type freely generated by "zero is a natural number" and "the successor of a natural number is a natural number". You can prove a theorem `P n` about `n : Nat` by `induction n`, which will expect a proof of the theorem for `P 0`, and a proof of `P (succ i)` assuming a proof of `P i`. The same method also works to define functions by recursion on natural numbers: induction and recursion are two expressions of the same operation from Lean's point of view. ``` open Nat example (n : Nat) : n < succ n := by induction n with | zero => show 0 < 1 decide | succ i ih => -- ih : i < succ i show succ i < succ (succ i) exact Nat.succ_lt_succ ih ``` This type is special-cased by both the kernel and the compiler: * The type of expressions contains "`Nat` literals" as a primitive constructor, and the kernel knows how to reduce zero/succ expressions to nat literals. * If implemented naively, this type would represent a numeral `n` in unary as a linked list with `n` links, which is horribly inefficient. Instead, the runtime itself has a special representation for `Nat` which stores numbers up to 2^63 directly and larger numbers use an arbitrary precision "bignum" library (usually [GMP](https://gmplib.org/)).
halfNat:NatNat : TypeThe type of natural numbers, starting at zero. It is defined as an inductive type freely generated by "zero is a natural number" and "the successor of a natural number is a natural number". You can prove a theorem `P n` about `n : Nat` by `induction n`, which will expect a proof of the theorem for `P 0`, and a proof of `P (succ i)` assuming a proof of `P i`. The same method also works to define functions by recursion on natural numbers: induction and recursion are two expressions of the same operation from Lean's point of view. ``` open Nat example (n : Nat) : n < succ n := by induction n with | zero => show 0 < 1 decide | succ i ih => -- ih : i < succ i show succ i < succ (succ i) exact Nat.succ_lt_succ ih ``` This type is special-cased by both the kernel and the compiler: * The type of expressions contains "`Nat` literals" as a primitive constructor, and the kernel knows how to reduce zero/succ expressions to nat literals. * If implemented naively, this type would represent a numeral `n` in unary as a linked list with `n` links, which is horribly inefficient. Instead, the runtime itself has a special representation for `Nat` which stores numbers up to 2^63 directly and larger numbers use an arbitrary precision "bignum" library (usually [GMP](https://gmplib.org/)).
prfn' = 2 * half:n'Nat = Eq.{u_1} {α : Sort u_1} (a✝a✝¹ : α) : PropThe equality relation. It has one introduction rule, `Eq.refl`. We use `a = b` as notation for `Eq a b`. A fundamental property of equality is that it is an equivalence relation. ``` variable (α : Type) (a b c d : α) variable (hab : a = b) (hcb : c = b) (hcd : c = d) example : a = d := Eq.trans (Eq.trans hab (Eq.symm hcb)) hcd ``` Equality is much more than an equivalence relation, however. It has the important property that every assertion respects the equivalence, in the sense that we can substitute equal expressions without changing the truth value. That is, given `h1 : a = b` and `h2 : p a`, we can construct a proof for `p b` using substitution: `Eq.subst h1 h2`. Example: ``` example (α : Type) (a b : α) (p : α → Prop) (h1 : a = b) (h2 : p a) : p b := Eq.subst h1 h2 example (α : Type) (a b : α) (p : α → Prop) (h1 : a = b) (h2 : p a) : p b := h1 ▸ h2 ``` The triangle in the second presentation is a macro built on top of `Eq.subst` and `Eq.symm`, and you can enter it by typing `\t`. For more information: [Equality](https://lean-lang.org/theorem_proving_in_lean4/quantifiers_and_equality.html#equality) 2 * HMul.hMul.{u, v, w} {α : Type u} {β : Type v} {γ : outParam (Type w)} [self : HMul α β γ] (a✝ : α) (a✝¹ : β) : γ`a * b` computes the product of `a` and `b`. The meaning of this notation is type-dependent. halfNat
(∃ half, Nat.succNat.succ (n : Nat) : NatThe successor function on natural numbers, `succ n = n + 1`. This is one of the two constructors of `Nat`. n'Nat = Eq.{u_1} {α : Sort u_1} (a✝a✝¹ : α) : PropThe equality relation. It has one introduction rule, `Eq.refl`. We use `a = b` as notation for `Eq a b`. A fundamental property of equality is that it is an equivalence relation. ``` variable (α : Type) (a b c d : α) variable (hab : a = b) (hcb : c = b) (hcd : c = d) example : a = d := Eq.trans (Eq.trans hab (Eq.symm hcb)) hcd ``` Equality is much more than an equivalence relation, however. It has the important property that every assertion respects the equivalence, in the sense that we can substitute equal expressions without changing the truth value. That is, given `h1 : a = b` and `h2 : p a`, we can construct a proof for `p b` using substitution: `Eq.subst h1 h2`. Example: ``` example (α : Type) (a b : α) (p : α → Prop) (h1 : a = b) (h2 : p a) : p b := Eq.subst h1 h2 example (α : Type) (a b : α) (p : α → Prop) (h1 : a = b) (h2 : p a) : p b := h1 ▸ h2 ``` The triangle in the second presentation is a macro built on top of `Eq.subst` and `Eq.symm`, and you can enter it by typing `\t`. For more information: [Equality](https://lean-lang.org/theorem_proving_in_lean4/quantifiers_and_equality.html#equality) 2 * HMul.hMul.{u, v, w} {α : Type u} {β : Type v} {γ : outParam (Type w)} [self : HMul α β γ] (a✝ : α) (a✝¹ : β) : γ`a * b` computes the product of `a` and `b`. The meaning of this notation is type-dependent. halfNat)Or (a b : Prop) : Prop`Or a b`, or `a ∨ b`, is the disjunction of propositions. There are two constructors for `Or`, called `Or.inl : a → a ∨ b` and `Or.inr : b → a ∨ b`, and you can use `match` or `cases` to destruct an `Or` assumption into the two cases. ∃ half, Nat.succNat.succ (n : Nat) : NatThe successor function on natural numbers, `succ n = n + 1`. This is one of the two constructors of `Nat`. n'Nat = Eq.{u_1} {α : Sort u_1} (a✝a✝¹ : α) : PropThe equality relation. It has one introduction rule, `Eq.refl`. We use `a = b` as notation for `Eq a b`. A fundamental property of equality is that it is an equivalence relation. ``` variable (α : Type) (a b c d : α) variable (hab : a = b) (hcb : c = b) (hcd : c = d) example : a = d := Eq.trans (Eq.trans hab (Eq.symm hcb)) hcd ``` Equality is much more than an equivalence relation, however. It has the important property that every assertion respects the equivalence, in the sense that we can substitute equal expressions without changing the truth value. That is, given `h1 : a = b` and `h2 : p a`, we can construct a proof for `p b` using substitution: `Eq.subst h1 h2`. Example: ``` example (α : Type) (a b : α) (p : α → Prop) (h1 : a = b) (h2 : p a) : p b := Eq.subst h1 h2 example (α : Type) (a b : α) (p : α → Prop) (h1 : a = b) (h2 : p a) : p b := h1 ▸ h2 ``` The triangle in the second presentation is a macro built on top of `Eq.subst` and `Eq.symm`, and you can enter it by typing `\t`. For more information: [Equality](https://lean-lang.org/theorem_proving_in_lean4/quantifiers_and_equality.html#equality) 2 * HMul.hMul.{u, v, w} {α : Type u} {β : Type v} {γ : outParam (Type w)} [self : HMul α β γ] (a✝ : α) (a✝¹ : β) : γ`a * b` computes the product of `a` and `b`. The meaning of this notation is type-dependent. halfNat + HAdd.hAdd.{u, v, w} {α : Type u} {β : Type v} {γ : outParam (Type w)} [self : HAdd α β γ] (a✝ : α) (a✝¹ : β) : γ`a + b` computes the sum of `a` and `b`. The meaning of this notation is type-dependent. 1
succ.inl.intro.h
n'Nat:NatNat : TypeThe type of natural numbers, starting at zero. It is defined as an inductive type freely generated by "zero is a natural number" and "the successor of a natural number is a natural number". You can prove a theorem `P n` about `n : Nat` by `induction n`, which will expect a proof of the theorem for `P 0`, and a proof of `P (succ i)` assuming a proof of `P i`. The same method also works to define functions by recursion on natural numbers: induction and recursion are two expressions of the same operation from Lean's point of view. ``` open Nat example (n : Nat) : n < succ n := by induction n with | zero => show 0 < 1 decide | succ i ih => -- ih : i < succ i show succ i < succ (succ i) exact Nat.succ_lt_succ ih ``` This type is special-cased by both the kernel and the compiler: * The type of expressions contains "`Nat` literals" as a primitive constructor, and the kernel knows how to reduce zero/succ expressions to nat literals. * If implemented naively, this type would represent a numeral `n` in unary as a linked list with `n` links, which is horribly inefficient. Instead, the runtime itself has a special representation for `Nat` which stores numbers up to 2^63 directly and larger numbers use an arbitrary precision "bignum" library (usually [GMP](https://gmplib.org/)).
halfNat:NatNat : TypeThe type of natural numbers, starting at zero. It is defined as an inductive type freely generated by "zero is a natural number" and "the successor of a natural number is a natural number". You can prove a theorem `P n` about `n : Nat` by `induction n`, which will expect a proof of the theorem for `P 0`, and a proof of `P (succ i)` assuming a proof of `P i`. The same method also works to define functions by recursion on natural numbers: induction and recursion are two expressions of the same operation from Lean's point of view. ``` open Nat example (n : Nat) : n < succ n := by induction n with | zero => show 0 < 1 decide | succ i ih => -- ih : i < succ i show succ i < succ (succ i) exact Nat.succ_lt_succ ih ``` This type is special-cased by both the kernel and the compiler: * The type of expressions contains "`Nat` literals" as a primitive constructor, and the kernel knows how to reduce zero/succ expressions to nat literals. * If implemented naively, this type would represent a numeral `n` in unary as a linked list with `n` links, which is horribly inefficient. Instead, the runtime itself has a special representation for `Nat` which stores numbers up to 2^63 directly and larger numbers use an arbitrary precision "bignum" library (usually [GMP](https://gmplib.org/)).
prfn' = 2 * half:n'Nat = Eq.{u_1} {α : Sort u_1} (a✝a✝¹ : α) : PropThe equality relation. It has one introduction rule, `Eq.refl`. We use `a = b` as notation for `Eq a b`. A fundamental property of equality is that it is an equivalence relation. ``` variable (α : Type) (a b c d : α) variable (hab : a = b) (hcb : c = b) (hcd : c = d) example : a = d := Eq.trans (Eq.trans hab (Eq.symm hcb)) hcd ``` Equality is much more than an equivalence relation, however. It has the important property that every assertion respects the equivalence, in the sense that we can substitute equal expressions without changing the truth value. That is, given `h1 : a = b` and `h2 : p a`, we can construct a proof for `p b` using substitution: `Eq.subst h1 h2`. Example: ``` example (α : Type) (a b : α) (p : α → Prop) (h1 : a = b) (h2 : p a) : p b := Eq.subst h1 h2 example (α : Type) (a b : α) (p : α → Prop) (h1 : a = b) (h2 : p a) : p b := h1 ▸ h2 ``` The triangle in the second presentation is a macro built on top of `Eq.subst` and `Eq.symm`, and you can enter it by typing `\t`. For more information: [Equality](https://lean-lang.org/theorem_proving_in_lean4/quantifiers_and_equality.html#equality) 2 * HMul.hMul.{u, v, w} {α : Type u} {β : Type v} {γ : outParam (Type w)} [self : HMul α β γ] (a✝ : α) (a✝¹ : β) : γ`a * b` computes the product of `a` and `b`. The meaning of this notation is type-dependent. halfNat
∃ half, Nat.succNat.succ (n : Nat) : NatThe successor function on natural numbers, `succ n = n + 1`. This is one of the two constructors of `Nat`. n'Nat = Eq.{u_1} {α : Sort u_1} (a✝a✝¹ : α) : PropThe equality relation. It has one introduction rule, `Eq.refl`. We use `a = b` as notation for `Eq a b`. A fundamental property of equality is that it is an equivalence relation. ``` variable (α : Type) (a b c d : α) variable (hab : a = b) (hcb : c = b) (hcd : c = d) example : a = d := Eq.trans (Eq.trans hab (Eq.symm hcb)) hcd ``` Equality is much more than an equivalence relation, however. It has the important property that every assertion respects the equivalence, in the sense that we can substitute equal expressions without changing the truth value. That is, given `h1 : a = b` and `h2 : p a`, we can construct a proof for `p b` using substitution: `Eq.subst h1 h2`. Example: ``` example (α : Type) (a b : α) (p : α → Prop) (h1 : a = b) (h2 : p a) : p b := Eq.subst h1 h2 example (α : Type) (a b : α) (p : α → Prop) (h1 : a = b) (h2 : p a) : p b := h1 ▸ h2 ``` The triangle in the second presentation is a macro built on top of `Eq.subst` and `Eq.symm`, and you can enter it by typing `\t`. For more information: [Equality](https://lean-lang.org/theorem_proving_in_lean4/quantifiers_and_equality.html#equality) 2 * HMul.hMul.{u, v, w} {α : Type u} {β : Type v} {γ : outParam (Type w)} [self : HMul α β γ] (a✝ : α) (a✝¹ : β) : γ`a * b` computes the product of `a` and `b`. The meaning of this notation is type-dependent. halfNat + HAdd.hAdd.{u, v, w} {α : Type u} {β : Type v} {γ : outParam (Type w)} [self : HAdd α β γ] (a✝ : α) (a✝¹ : β) : γ`a + b` computes the sum of `a` and `b`. The meaning of this notation is type-dependent. 1
All goals completed! 🐙
succ.inr.intro
n'Nat:NatNat : TypeThe type of natural numbers, starting at zero. It is defined as an inductive type freely generated by "zero is a natural number" and "the successor of a natural number is a natural number". You can prove a theorem `P n` about `n : Nat` by `induction n`, which will expect a proof of the theorem for `P 0`, and a proof of `P (succ i)` assuming a proof of `P i`. The same method also works to define functions by recursion on natural numbers: induction and recursion are two expressions of the same operation from Lean's point of view. ``` open Nat example (n : Nat) : n < succ n := by induction n with | zero => show 0 < 1 decide | succ i ih => -- ih : i < succ i show succ i < succ (succ i) exact Nat.succ_lt_succ ih ``` This type is special-cased by both the kernel and the compiler: * The type of expressions contains "`Nat` literals" as a primitive constructor, and the kernel knows how to reduce zero/succ expressions to nat literals. * If implemented naively, this type would represent a numeral `n` in unary as a linked list with `n` links, which is horribly inefficient. Instead, the runtime itself has a special representation for `Nat` which stores numbers up to 2^63 directly and larger numbers use an arbitrary precision "bignum" library (usually [GMP](https://gmplib.org/)).
halfNat:NatNat : TypeThe type of natural numbers, starting at zero. It is defined as an inductive type freely generated by "zero is a natural number" and "the successor of a natural number is a natural number". You can prove a theorem `P n` about `n : Nat` by `induction n`, which will expect a proof of the theorem for `P 0`, and a proof of `P (succ i)` assuming a proof of `P i`. The same method also works to define functions by recursion on natural numbers: induction and recursion are two expressions of the same operation from Lean's point of view. ``` open Nat example (n : Nat) : n < succ n := by induction n with | zero => show 0 < 1 decide | succ i ih => -- ih : i < succ i show succ i < succ (succ i) exact Nat.succ_lt_succ ih ``` This type is special-cased by both the kernel and the compiler: * The type of expressions contains "`Nat` literals" as a primitive constructor, and the kernel knows how to reduce zero/succ expressions to nat literals. * If implemented naively, this type would represent a numeral `n` in unary as a linked list with `n` links, which is horribly inefficient. Instead, the runtime itself has a special representation for `Nat` which stores numbers up to 2^63 directly and larger numbers use an arbitrary precision "bignum" library (usually [GMP](https://gmplib.org/)).
prfn' = 2 * half + 1:n'Nat = Eq.{u_1} {α : Sort u_1} (a✝a✝¹ : α) : PropThe equality relation. It has one introduction rule, `Eq.refl`. We use `a = b` as notation for `Eq a b`. A fundamental property of equality is that it is an equivalence relation. ``` variable (α : Type) (a b c d : α) variable (hab : a = b) (hcb : c = b) (hcd : c = d) example : a = d := Eq.trans (Eq.trans hab (Eq.symm hcb)) hcd ``` Equality is much more than an equivalence relation, however. It has the important property that every assertion respects the equivalence, in the sense that we can substitute equal expressions without changing the truth value. That is, given `h1 : a = b` and `h2 : p a`, we can construct a proof for `p b` using substitution: `Eq.subst h1 h2`. Example: ``` example (α : Type) (a b : α) (p : α → Prop) (h1 : a = b) (h2 : p a) : p b := Eq.subst h1 h2 example (α : Type) (a b : α) (p : α → Prop) (h1 : a = b) (h2 : p a) : p b := h1 ▸ h2 ``` The triangle in the second presentation is a macro built on top of `Eq.subst` and `Eq.symm`, and you can enter it by typing `\t`. For more information: [Equality](https://lean-lang.org/theorem_proving_in_lean4/quantifiers_and_equality.html#equality) 2 * HMul.hMul.{u, v, w} {α : Type u} {β : Type v} {γ : outParam (Type w)} [self : HMul α β γ] (a✝ : α) (a✝¹ : β) : γ`a * b` computes the product of `a` and `b`. The meaning of this notation is type-dependent. halfNat + HAdd.hAdd.{u, v, w} {α : Type u} {β : Type v} {γ : outParam (Type w)} [self : HAdd α β γ] (a✝ : α) (a✝¹ : β) : γ`a + b` computes the sum of `a` and `b`. The meaning of this notation is type-dependent. 1
(∃ half, Nat.succNat.succ (n : Nat) : NatThe successor function on natural numbers, `succ n = n + 1`. This is one of the two constructors of `Nat`. n'Nat = Eq.{u_1} {α : Sort u_1} (a✝a✝¹ : α) : PropThe equality relation. It has one introduction rule, `Eq.refl`. We use `a = b` as notation for `Eq a b`. A fundamental property of equality is that it is an equivalence relation. ``` variable (α : Type) (a b c d : α) variable (hab : a = b) (hcb : c = b) (hcd : c = d) example : a = d := Eq.trans (Eq.trans hab (Eq.symm hcb)) hcd ``` Equality is much more than an equivalence relation, however. It has the important property that every assertion respects the equivalence, in the sense that we can substitute equal expressions without changing the truth value. That is, given `h1 : a = b` and `h2 : p a`, we can construct a proof for `p b` using substitution: `Eq.subst h1 h2`. Example: ``` example (α : Type) (a b : α) (p : α → Prop) (h1 : a = b) (h2 : p a) : p b := Eq.subst h1 h2 example (α : Type) (a b : α) (p : α → Prop) (h1 : a = b) (h2 : p a) : p b := h1 ▸ h2 ``` The triangle in the second presentation is a macro built on top of `Eq.subst` and `Eq.symm`, and you can enter it by typing `\t`. For more information: [Equality](https://lean-lang.org/theorem_proving_in_lean4/quantifiers_and_equality.html#equality) 2 * HMul.hMul.{u, v, w} {α : Type u} {β : Type v} {γ : outParam (Type w)} [self : HMul α β γ] (a✝ : α) (a✝¹ : β) : γ`a * b` computes the product of `a` and `b`. The meaning of this notation is type-dependent. halfNat)Or (a b : Prop) : Prop`Or a b`, or `a ∨ b`, is the disjunction of propositions. There are two constructors for `Or`, called `Or.inl : a → a ∨ b` and `Or.inr : b → a ∨ b`, and you can use `match` or `cases` to destruct an `Or` assumption into the two cases. ∃ half, Nat.succNat.succ (n : Nat) : NatThe successor function on natural numbers, `succ n = n + 1`. This is one of the two constructors of `Nat`. n'Nat = Eq.{u_1} {α : Sort u_1} (a✝a✝¹ : α) : PropThe equality relation. It has one introduction rule, `Eq.refl`. We use `a = b` as notation for `Eq a b`. A fundamental property of equality is that it is an equivalence relation. ``` variable (α : Type) (a b c d : α) variable (hab : a = b) (hcb : c = b) (hcd : c = d) example : a = d := Eq.trans (Eq.trans hab (Eq.symm hcb)) hcd ``` Equality is much more than an equivalence relation, however. It has the important property that every assertion respects the equivalence, in the sense that we can substitute equal expressions without changing the truth value. That is, given `h1 : a = b` and `h2 : p a`, we can construct a proof for `p b` using substitution: `Eq.subst h1 h2`. Example: ``` example (α : Type) (a b : α) (p : α → Prop) (h1 : a = b) (h2 : p a) : p b := Eq.subst h1 h2 example (α : Type) (a b : α) (p : α → Prop) (h1 : a = b) (h2 : p a) : p b := h1 ▸ h2 ``` The triangle in the second presentation is a macro built on top of `Eq.subst` and `Eq.symm`, and you can enter it by typing `\t`. For more information: [Equality](https://lean-lang.org/theorem_proving_in_lean4/quantifiers_and_equality.html#equality) 2 * HMul.hMul.{u, v, w} {α : Type u} {β : Type v} {γ : outParam (Type w)} [self : HMul α β γ] (a✝ : α) (a✝¹ : β) : γ`a * b` computes the product of `a` and `b`. The meaning of this notation is type-dependent. halfNat + HAdd.hAdd.{u, v, w} {α : Type u} {β : Type v} {γ : outParam (Type w)} [self : HAdd α β γ] (a✝ : α) (a✝¹ : β) : γ`a + b` computes the sum of `a` and `b`. The meaning of this notation is type-dependent. 1
succ.inr.intro.h
n'Nat:NatNat : TypeThe type of natural numbers, starting at zero. It is defined as an inductive type freely generated by "zero is a natural number" and "the successor of a natural number is a natural number". You can prove a theorem `P n` about `n : Nat` by `induction n`, which will expect a proof of the theorem for `P 0`, and a proof of `P (succ i)` assuming a proof of `P i`. The same method also works to define functions by recursion on natural numbers: induction and recursion are two expressions of the same operation from Lean's point of view. ``` open Nat example (n : Nat) : n < succ n := by induction n with | zero => show 0 < 1 decide | succ i ih => -- ih : i < succ i show succ i < succ (succ i) exact Nat.succ_lt_succ ih ``` This type is special-cased by both the kernel and the compiler: * The type of expressions contains "`Nat` literals" as a primitive constructor, and the kernel knows how to reduce zero/succ expressions to nat literals. * If implemented naively, this type would represent a numeral `n` in unary as a linked list with `n` links, which is horribly inefficient. Instead, the runtime itself has a special representation for `Nat` which stores numbers up to 2^63 directly and larger numbers use an arbitrary precision "bignum" library (usually [GMP](https://gmplib.org/)).
halfNat:NatNat : TypeThe type of natural numbers, starting at zero. It is defined as an inductive type freely generated by "zero is a natural number" and "the successor of a natural number is a natural number". You can prove a theorem `P n` about `n : Nat` by `induction n`, which will expect a proof of the theorem for `P 0`, and a proof of `P (succ i)` assuming a proof of `P i`. The same method also works to define functions by recursion on natural numbers: induction and recursion are two expressions of the same operation from Lean's point of view. ``` open Nat example (n : Nat) : n < succ n := by induction n with | zero => show 0 < 1 decide | succ i ih => -- ih : i < succ i show succ i < succ (succ i) exact Nat.succ_lt_succ ih ``` This type is special-cased by both the kernel and the compiler: * The type of expressions contains "`Nat` literals" as a primitive constructor, and the kernel knows how to reduce zero/succ expressions to nat literals. * If implemented naively, this type would represent a numeral `n` in unary as a linked list with `n` links, which is horribly inefficient. Instead, the runtime itself has a special representation for `Nat` which stores numbers up to 2^63 directly and larger numbers use an arbitrary precision "bignum" library (usually [GMP](https://gmplib.org/)).
prfn' = 2 * half + 1:n'Nat = Eq.{u_1} {α : Sort u_1} (a✝a✝¹ : α) : PropThe equality relation. It has one introduction rule, `Eq.refl`. We use `a = b` as notation for `Eq a b`. A fundamental property of equality is that it is an equivalence relation. ``` variable (α : Type) (a b c d : α) variable (hab : a = b) (hcb : c = b) (hcd : c = d) example : a = d := Eq.trans (Eq.trans hab (Eq.symm hcb)) hcd ``` Equality is much more than an equivalence relation, however. It has the important property that every assertion respects the equivalence, in the sense that we can substitute equal expressions without changing the truth value. That is, given `h1 : a = b` and `h2 : p a`, we can construct a proof for `p b` using substitution: `Eq.subst h1 h2`. Example: ``` example (α : Type) (a b : α) (p : α → Prop) (h1 : a = b) (h2 : p a) : p b := Eq.subst h1 h2 example (α : Type) (a b : α) (p : α → Prop) (h1 : a = b) (h2 : p a) : p b := h1 ▸ h2 ``` The triangle in the second presentation is a macro built on top of `Eq.subst` and `Eq.symm`, and you can enter it by typing `\t`. For more information: [Equality](https://lean-lang.org/theorem_proving_in_lean4/quantifiers_and_equality.html#equality) 2 * HMul.hMul.{u, v, w} {α : Type u} {β : Type v} {γ : outParam (Type w)} [self : HMul α β γ] (a✝ : α) (a✝¹ : β) : γ`a * b` computes the product of `a` and `b`. The meaning of this notation is type-dependent. halfNat + HAdd.hAdd.{u, v, w} {α : Type u} {β : Type v} {γ : outParam (Type w)} [self : HAdd α β γ] (a✝ : α) (a✝¹ : β) : γ`a + b` computes the sum of `a` and `b`. The meaning of this notation is type-dependent. 1
∃ half, Nat.succNat.succ (n : Nat) : NatThe successor function on natural numbers, `succ n = n + 1`. This is one of the two constructors of `Nat`. n'Nat = Eq.{u_1} {α : Sort u_1} (a✝a✝¹ : α) : PropThe equality relation. It has one introduction rule, `Eq.refl`. We use `a = b` as notation for `Eq a b`. A fundamental property of equality is that it is an equivalence relation. ``` variable (α : Type) (a b c d : α) variable (hab : a = b) (hcb : c = b) (hcd : c = d) example : a = d := Eq.trans (Eq.trans hab (Eq.symm hcb)) hcd ``` Equality is much more than an equivalence relation, however. It has the important property that every assertion respects the equivalence, in the sense that we can substitute equal expressions without changing the truth value. That is, given `h1 : a = b` and `h2 : p a`, we can construct a proof for `p b` using substitution: `Eq.subst h1 h2`. Example: ``` example (α : Type) (a b : α) (p : α → Prop) (h1 : a = b) (h2 : p a) : p b := Eq.subst h1 h2 example (α : Type) (a b : α) (p : α → Prop) (h1 : a = b) (h2 : p a) : p b := h1 ▸ h2 ``` The triangle in the second presentation is a macro built on top of `Eq.subst` and `Eq.symm`, and you can enter it by typing `\t`. For more information: [Equality](https://lean-lang.org/theorem_proving_in_lean4/quantifiers_and_equality.html#equality) 2 * HMul.hMul.{u, v, w} {α : Type u} {β : Type v} {γ : outParam (Type w)} [self : HMul α β γ] (a✝ : α) (a✝¹ : β) : γ`a * b` computes the product of `a` and `b`. The meaning of this notation is type-dependent. halfNat
succ.inr.intro.h
n'Nat:NatNat : TypeThe type of natural numbers, starting at zero. It is defined as an inductive type freely generated by "zero is a natural number" and "the successor of a natural number is a natural number". You can prove a theorem `P n` about `n : Nat` by `induction n`, which will expect a proof of the theorem for `P 0`, and a proof of `P (succ i)` assuming a proof of `P i`. The same method also works to define functions by recursion on natural numbers: induction and recursion are two expressions of the same operation from Lean's point of view. ``` open Nat example (n : Nat) : n < succ n := by induction n with | zero => show 0 < 1 decide | succ i ih => -- ih : i < succ i show succ i < succ (succ i) exact Nat.succ_lt_succ ih ``` This type is special-cased by both the kernel and the compiler: * The type of expressions contains "`Nat` literals" as a primitive constructor, and the kernel knows how to reduce zero/succ expressions to nat literals. * If implemented naively, this type would represent a numeral `n` in unary as a linked list with `n` links, which is horribly inefficient. Instead, the runtime itself has a special representation for `Nat` which stores numbers up to 2^63 directly and larger numbers use an arbitrary precision "bignum" library (usually [GMP](https://gmplib.org/)).
halfNat:NatNat : TypeThe type of natural numbers, starting at zero. It is defined as an inductive type freely generated by "zero is a natural number" and "the successor of a natural number is a natural number". You can prove a theorem `P n` about `n : Nat` by `induction n`, which will expect a proof of the theorem for `P 0`, and a proof of `P (succ i)` assuming a proof of `P i`. The same method also works to define functions by recursion on natural numbers: induction and recursion are two expressions of the same operation from Lean's point of view. ``` open Nat example (n : Nat) : n < succ n := by induction n with | zero => show 0 < 1 decide | succ i ih => -- ih : i < succ i show succ i < succ (succ i) exact Nat.succ_lt_succ ih ``` This type is special-cased by both the kernel and the compiler: * The type of expressions contains "`Nat` literals" as a primitive constructor, and the kernel knows how to reduce zero/succ expressions to nat literals. * If implemented naively, this type would represent a numeral `n` in unary as a linked list with `n` links, which is horribly inefficient. Instead, the runtime itself has a special representation for `Nat` which stores numbers up to 2^63 directly and larger numbers use an arbitrary precision "bignum" library (usually [GMP](https://gmplib.org/)).
prfn' = 2 * half + 1:n'Nat = Eq.{u_1} {α : Sort u_1} (a✝a✝¹ : α) : PropThe equality relation. It has one introduction rule, `Eq.refl`. We use `a = b` as notation for `Eq a b`. A fundamental property of equality is that it is an equivalence relation. ``` variable (α : Type) (a b c d : α) variable (hab : a = b) (hcb : c = b) (hcd : c = d) example : a = d := Eq.trans (Eq.trans hab (Eq.symm hcb)) hcd ``` Equality is much more than an equivalence relation, however. It has the important property that every assertion respects the equivalence, in the sense that we can substitute equal expressions without changing the truth value. That is, given `h1 : a = b` and `h2 : p a`, we can construct a proof for `p b` using substitution: `Eq.subst h1 h2`. Example: ``` example (α : Type) (a b : α) (p : α → Prop) (h1 : a = b) (h2 : p a) : p b := Eq.subst h1 h2 example (α : Type) (a b : α) (p : α → Prop) (h1 : a = b) (h2 : p a) : p b := h1 ▸ h2 ``` The triangle in the second presentation is a macro built on top of `Eq.subst` and `Eq.symm`, and you can enter it by typing `\t`. For more information: [Equality](https://lean-lang.org/theorem_proving_in_lean4/quantifiers_and_equality.html#equality) 2 * HMul.hMul.{u, v, w} {α : Type u} {β : Type v} {γ : outParam (Type w)} [self : HMul α β γ] (a✝ : α) (a✝¹ : β) : γ`a * b` computes the product of `a` and `b`. The meaning of this notation is type-dependent. halfNat + HAdd.hAdd.{u, v, w} {α : Type u} {β : Type v} {γ : outParam (Type w)} [self : HAdd α β γ] (a✝ : α) (a✝¹ : β) : γ`a + b` computes the sum of `a` and `b`. The meaning of this notation is type-dependent. 1
∃ half_1, Nat.succNat.succ (n : Nat) : NatThe successor function on natural numbers, `succ n = n + 1`. This is one of the two constructors of `Nat`. (2 * HMul.hMul.{u, v, w} {α : Type u} {β : Type v} {γ : outParam (Type w)} [self : HMul α β γ] (a✝ : α) (a✝¹ : β) : γ`a * b` computes the product of `a` and `b`. The meaning of this notation is type-dependent. halfNat + HAdd.hAdd.{u, v, w} {α : Type u} {β : Type v} {γ : outParam (Type w)} [self : HAdd α β γ] (a✝ : α) (a✝¹ : β) : γ`a + b` computes the sum of `a` and `b`. The meaning of this notation is type-dependent. 1) = Eq.{u_1} {α : Sort u_1} (a✝a✝¹ : α) : PropThe equality relation. It has one introduction rule, `Eq.refl`. We use `a = b` as notation for `Eq a b`. A fundamental property of equality is that it is an equivalence relation. ``` variable (α : Type) (a b c d : α) variable (hab : a = b) (hcb : c = b) (hcd : c = d) example : a = d := Eq.trans (Eq.trans hab (Eq.symm hcb)) hcd ``` Equality is much more than an equivalence relation, however. It has the important property that every assertion respects the equivalence, in the sense that we can substitute equal expressions without changing the truth value. That is, given `h1 : a = b` and `h2 : p a`, we can construct a proof for `p b` using substitution: `Eq.subst h1 h2`. Example: ``` example (α : Type) (a b : α) (p : α → Prop) (h1 : a = b) (h2 : p a) : p b := Eq.subst h1 h2 example (α : Type) (a b : α) (p : α → Prop) (h1 : a = b) (h2 : p a) : p b := h1 ▸ h2 ``` The triangle in the second presentation is a macro built on top of `Eq.subst` and `Eq.symm`, and you can enter it by typing `\t`. For more information: [Equality](https://lean-lang.org/theorem_proving_in_lean4/quantifiers_and_equality.html#equality) 2 * HMul.hMul.{u, v, w} {α : Type u} {β : Type v} {γ : outParam (Type w)} [self : HMul α β γ] (a✝ : α) (a✝¹ : β) : γ`a * b` computes the product of `a` and `b`. The meaning of this notation is type-dependent. half_1Nat
All goals completed! 🐙

If you have a background in dependent type theory, don't let the name of solve_by_elim throw you off; it's not a reference to the use of eliminators of inductive types. This is a very old tactic that has been ported from prior versions of Lean. Historically, elim-lemmas were those used by various parts of proof automation, and the name of the tactic stuck even when the concept of elim-lemmas no longer existed. The tactic was originally written by Simon Hudon, and later rewritten by Kim Morrison.

simpa

simpa is a specialized version of simp, designed exclusively for closing goals. Like rcases, it was written by Mario Carneiro. It can be provided a term argument with using, in which case it simplifies both the goal and the term's type before using the term to close the goal. Without a using argument, it will use an assumption called this as the term, simplifying both the goal and the assumption's type. Simplifying both types the same way makes the proof more robust to changes in the simp set.

As an example, the proof split_lengthsplit_length.{u_1} {α : Type u_1} (xs : List α) : List.length (split xs).fst + List.length (split xs).snd = List.length xs that splitting a list results in two lists whose lengths sum to the original length can use simpa instead of omega:

theorem split_lengthsplit_length.{u_1} {α : Type u_1} (xs : List α) : List.length (split xs).fst + List.length (split xs).snd = List.length xs (xsList α : ListList.{u} (α : Type u) : Type u`List α` is the type of ordered lists with elements of type `α`. It is implemented as a linked list. `List α` is isomorphic to `Array α`, but they are useful for different things: * `List α` is easier for reasoning, and `Array α` is modeled as a wrapper around `List α` * `List α` works well as a persistent data structure, when many copies of the tail are shared. When the value is not shared, `Array α` will have better performance because it can do destructive updates. αType u_1) : (splitsplit.{u_1} {α : Type u_1} (a✝ : List α) : List α × List α xsList α).fstProd.fst.{u, v} {α : Type u} {β : Type v} (self : α × β) : αThe first projection out of a pair. if `p : α × β` then `p.1 : α`. .lengthList.length.{u_1} {α : Type u_1} (a✝ : List α) : NatThe length of a list: `[].length = 0` and `(a :: l).length = l.length + 1`. This function is overridden in the compiler to `lengthTR`, which uses constant stack space, while leaving this function to use the "naive" recursion which is easier for reasoning. + (splitsplit.{u_1} {α : Type u_1} (a✝ : List α) : List α × List α xsList α).sndProd.snd.{u, v} {α : Type u} {β : Type v} (self : α × β) : βThe second projection out of a pair. if `p : α × β` then `p.2 : β`. .lengthList.length.{u_1} {α : Type u_1} (a✝ : List α) : NatThe length of a list: `[].length = 0` and `(a :: l).length = l.length + 1`. This function is overridden in the compiler to `lengthTR`, which uses constant stack space, while leaving this function to use the "naive" recursion which is easier for reasoning. = xsList α.lengthList.length.{u_1} {α : Type u_1} (a✝ : List α) : NatThe length of a list: `[].length = 0` and `(a :: l).length = l.length + 1`. This function is overridden in the compiler to `lengthTR`, which uses constant stack space, while leaving this function to use the "naive" recursion which is easier for reasoning. :=
αType u_1:Type u_1
xsList α:ListList.{u} (α : Type u) : Type u`List α` is the type of ordered lists with elements of type `α`. It is implemented as a linked list. `List α` is isomorphic to `Array α`, but they are useful for different things: * `List α` is easier for reasoning, and `Array α` is modeled as a wrapper around `List α` * `List α` works well as a persistent data structure, when many copies of the tail are shared. When the value is not shared, `Array α` will have better performance because it can do destructive updates. αType u_1
List.lengthList.length.{u_1} {α : Type u_1} (a✝ : List α) : NatThe length of a list: `[].length = 0` and `(a :: l).length = l.length + 1`. This function is overridden in the compiler to `lengthTR`, which uses constant stack space, while leaving this function to use the "naive" recursion which is easier for reasoning. (splitsplit.{u_1} {α : Type u_1} (a✝ : List α) : List α × List α xsList α).fst + HAdd.hAdd.{u, v, w} {α : Type u} {β : Type v} {γ : outParam (Type w)} [self : HAdd α β γ] (a✝ : α) (a✝¹ : β) : γ`a + b` computes the sum of `a` and `b`. The meaning of this notation is type-dependent. List.lengthList.length.{u_1} {α : Type u_1} (a✝ : List α) : NatThe length of a list: `[].length = 0` and `(a :: l).length = l.length + 1`. This function is overridden in the compiler to `lengthTR`, which uses constant stack space, while leaving this function to use the "naive" recursion which is easier for reasoning. (splitsplit.{u_1} {α : Type u_1} (a✝ : List α) : List α × List α xsList α).snd = Eq.{u_1} {α : Sort u_1} (a✝a✝¹ : α) : PropThe equality relation. It has one introduction rule, `Eq.refl`. We use `a = b` as notation for `Eq a b`. A fundamental property of equality is that it is an equivalence relation. ``` variable (α : Type) (a b c d : α) variable (hab : a = b) (hcb : c = b) (hcd : c = d) example : a = d := Eq.trans (Eq.trans hab (Eq.symm hcb)) hcd ``` Equality is much more than an equivalence relation, however. It has the important property that every assertion respects the equivalence, in the sense that we can substitute equal expressions without changing the truth value. That is, given `h1 : a = b` and `h2 : p a`, we can construct a proof for `p b` using substitution: `Eq.subst h1 h2`. Example: ``` example (α : Type) (a b : α) (p : α → Prop) (h1 : a = b) (h2 : p a) : p b := Eq.subst h1 h2 example (α : Type) (a b : α) (p : α → Prop) (h1 : a = b) (h2 : p a) : p b := h1 ▸ h2 ``` The triangle in the second presentation is a macro built on top of `Eq.subst` and `Eq.symm`, and you can enter it by typing `\t`. For more information: [Equality](https://lean-lang.org/theorem_proving_in_lean4/quantifiers_and_equality.html#equality) List.lengthList.length.{u_1} {α : Type u_1} (a✝ : List α) : NatThe length of a list: `[].length = 0` and `(a :: l).length = l.length + 1`. This function is overridden in the compiler to `lengthTR`, which uses constant stack space, while leaving this function to use the "naive" recursion which is easier for reasoning. xsList α
match`match` performs case analysis on one or more expressions. See [Induction and Recursion][tpil4]. The syntax for the `match` tactic is the same as term-mode `match`, except that the match arms are tactics instead of expressions. ``` example (n : Nat) : n = n := by match n with | 0 => rfl | i+1 => simp ``` [tpil4]: https://lean-lang.org/theorem_proving_in_lean4/induction_and_recursion.html xsList α with`match` performs case analysis on one or more expressions. See [Induction and Recursion][tpil4]. The syntax for the `match` tactic is the same as term-mode `match`, except that the match arms are tactics instead of expressions. ``` example (n : Nat) : n = n := by match n with | 0 => rfl | i+1 => simp ``` [tpil4]: https://lean-lang.org/theorem_proving_in_lean4/induction_and_recursion.html | [] =>
All goals completed! 🐙
| [yα] =>
All goals completed! 🐙
| yα :: y'α :: ysList α =>
αType u_1:Type u_1
xsList α:ListList.{u} (α : Type u) : Type u`List α` is the type of ordered lists with elements of type `α`. It is implemented as a linked list. `List α` is isomorphic to `Array α`, but they are useful for different things: * `List α` is easier for reasoning, and `Array α` is modeled as a wrapper around `List α` * `List α` works well as a persistent data structure, when many copies of the tail are shared. When the value is not shared, `Array α` will have better performance because it can do destructive updates. αType u_1
yα:αType u_1
y'α:αType u_1
ysList α:ListList.{u} (α : Type u) : Type u`List α` is the type of ordered lists with elements of type `α`. It is implemented as a linked list. `List α` is isomorphic to `Array α`, but they are useful for different things: * `List α` is easier for reasoning, and `Array α` is modeled as a wrapper around `List α` * `List α` works well as a persistent data structure, when many copies of the tail are shared. When the value is not shared, `Array α` will have better performance because it can do destructive updates. αType u_1
thisList.length (split ys).fst + List.length (split ys).snd = List.length ys:List.lengthList.length.{u_1} {α : Type u_1} (a✝ : List α) : NatThe length of a list: `[].length = 0` and `(a :: l).length = l.length + 1`. This function is overridden in the compiler to `lengthTR`, which uses constant stack space, while leaving this function to use the "naive" recursion which is easier for reasoning. (splitsplit.{u_1} {α : Type u_1} (a✝ : List α) : List α × List α ysList α).fst + HAdd.hAdd.{u, v, w} {α : Type u} {β : Type v} {γ : outParam (Type w)} [self : HAdd α β γ] (a✝ : α) (a✝¹ : β) : γ`a + b` computes the sum of `a` and `b`. The meaning of this notation is type-dependent. List.lengthList.length.{u_1} {α : Type u_1} (a✝ : List α) : NatThe length of a list: `[].length = 0` and `(a :: l).length = l.length + 1`. This function is overridden in the compiler to `lengthTR`, which uses constant stack space, while leaving this function to use the "naive" recursion which is easier for reasoning. (splitsplit.{u_1} {α : Type u_1} (a✝ : List α) : List α × List α ysList α).snd = Eq.{u_1} {α : Sort u_1} (a✝a✝¹ : α) : PropThe equality relation. It has one introduction rule, `Eq.refl`. We use `a = b` as notation for `Eq a b`. A fundamental property of equality is that it is an equivalence relation. ``` variable (α : Type) (a b c d : α) variable (hab : a = b) (hcb : c = b) (hcd : c = d) example : a = d := Eq.trans (Eq.trans hab (Eq.symm hcb)) hcd ``` Equality is much more than an equivalence relation, however. It has the important property that every assertion respects the equivalence, in the sense that we can substitute equal expressions without changing the truth value. That is, given `h1 : a = b` and `h2 : p a`, we can construct a proof for `p b` using substitution: `Eq.subst h1 h2`. Example: ``` example (α : Type) (a b : α) (p : α → Prop) (h1 : a = b) (h2 : p a) : p b := Eq.subst h1 h2 example (α : Type) (a b : α) (p : α → Prop) (h1 : a = b) (h2 : p a) : p b := h1 ▸ h2 ``` The triangle in the second presentation is a macro built on top of `Eq.subst` and `Eq.symm`, and you can enter it by typing `\t`. For more information: [Equality](https://lean-lang.org/theorem_proving_in_lean4/quantifiers_and_equality.html#equality) List.lengthList.length.{u_1} {α : Type u_1} (a✝ : List α) : NatThe length of a list: `[].length = 0` and `(a :: l).length = l.length + 1`. This function is overridden in the compiler to `lengthTR`, which uses constant stack space, while leaving this function to use the "naive" recursion which is easier for reasoning. ysList α
List.lengthList.length.{u_1} {α : Type u_1} (a✝ : List α) : NatThe length of a list: `[].length = 0` and `(a :: l).length = l.length + 1`. This function is overridden in the compiler to `lengthTR`, which uses constant stack space, while leaving this function to use the "naive" recursion which is easier for reasoning. (splitsplit.{u_1} {α : Type u_1} (a✝ : List α) : List α × List α (yα :: List.cons.{u} {α : Type u} (head : α) (tail : List α) : List αIf `a : α` and `l : List α`, then `cons a l`, or `a :: l`, is the list whose first element is `a` and with `l` as the rest of the list. y'α :: List.cons.{u} {α : Type u} (head : α) (tail : List α) : List αIf `a : α` and `l : List α`, then `cons a l`, or `a :: l`, is the list whose first element is `a` and with `l` as the rest of the list. ysList α)).fst + HAdd.hAdd.{u, v, w} {α : Type u} {β : Type v} {γ : outParam (Type w)} [self : HAdd α β γ] (a✝ : α) (a✝¹ : β) : γ`a + b` computes the sum of `a` and `b`. The meaning of this notation is type-dependent. List.lengthList.length.{u_1} {α : Type u_1} (a✝ : List α) : NatThe length of a list: `[].length = 0` and `(a :: l).length = l.length + 1`. This function is overridden in the compiler to `lengthTR`, which uses constant stack space, while leaving this function to use the "naive" recursion which is easier for reasoning. (splitsplit.{u_1} {α : Type u_1} (a✝ : List α) : List α × List α (yα :: List.cons.{u} {α : Type u} (head : α) (tail : List α) : List αIf `a : α` and `l : List α`, then `cons a l`, or `a :: l`, is the list whose first element is `a` and with `l` as the rest of the list. y'α :: List.cons.{u} {α : Type u} (head : α) (tail : List α) : List αIf `a : α` and `l : List α`, then `cons a l`, or `a :: l`, is the list whose first element is `a` and with `l` as the rest of the list. ysList α)).snd = Eq.{u_1} {α : Sort u_1} (a✝a✝¹ : α) : PropThe equality relation. It has one introduction rule, `Eq.refl`. We use `a = b` as notation for `Eq a b`. A fundamental property of equality is that it is an equivalence relation. ``` variable (α : Type) (a b c d : α) variable (hab : a = b) (hcb : c = b) (hcd : c = d) example : a = d := Eq.trans (Eq.trans hab (Eq.symm hcb)) hcd ``` Equality is much more than an equivalence relation, however. It has the important property that every assertion respects the equivalence, in the sense that we can substitute equal expressions without changing the truth value. That is, given `h1 : a = b` and `h2 : p a`, we can construct a proof for `p b` using substitution: `Eq.subst h1 h2`. Example: ``` example (α : Type) (a b : α) (p : α → Prop) (h1 : a = b) (h2 : p a) : p b := Eq.subst h1 h2 example (α : Type) (a b : α) (p : α → Prop) (h1 : a = b) (h2 : p a) : p b := h1 ▸ h2 ``` The triangle in the second presentation is a macro built on top of `Eq.subst` and `Eq.symm`, and you can enter it by typing `\t`. For more information: [Equality](https://lean-lang.org/theorem_proving_in_lean4/quantifiers_and_equality.html#equality) List.lengthList.length.{u_1} {α : Type u_1} (a✝ : List α) : NatThe length of a list: `[].length = 0` and `(a :: l).length = l.length + 1`. This function is overridden in the compiler to `lengthTR`, which uses constant stack space, while leaving this function to use the "naive" recursion which is easier for reasoning. (yα :: List.cons.{u} {α : Type u} (head : α) (tail : List α) : List αIf `a : α` and `l : List α`, then `cons a l`, or `a :: l`, is the list whose first element is `a` and with `l` as the rest of the list. y'α :: List.cons.{u} {α : Type u} (head : α) (tail : List α) : List αIf `a : α` and `l : List α`, then `cons a l`, or `a :: l`, is the list whose first element is `a` and with `l` as the rest of the list. ysList α)
αType u_1:Type u_1
xsList α:ListList.{u} (α : Type u) : Type u`List α` is the type of ordered lists with elements of type `α`. It is implemented as a linked list. `List α` is isomorphic to `Array α`, but they are useful for different things: * `List α` is easier for reasoning, and `Array α` is modeled as a wrapper around `List α` * `List α` works well as a persistent data structure, when many copies of the tail are shared. When the value is not shared, `Array α` will have better performance because it can do destructive updates. αType u_1
yα:αType u_1
y'α:αType u_1
ysList α:ListList.{u} (α : Type u) : Type u`List α` is the type of ordered lists with elements of type `α`. It is implemented as a linked list. `List α` is isomorphic to `Array α`, but they are useful for different things: * `List α` is easier for reasoning, and `Array α` is modeled as a wrapper around `List α` * `List α` works well as a persistent data structure, when many copies of the tail are shared. When the value is not shared, `Array α` will have better performance because it can do destructive updates. αType u_1
thisList.length (split ys).fst + List.length (split ys).snd = List.length ys:List.lengthList.length.{u_1} {α : Type u_1} (a✝ : List α) : NatThe length of a list: `[].length = 0` and `(a :: l).length = l.length + 1`. This function is overridden in the compiler to `lengthTR`, which uses constant stack space, while leaving this function to use the "naive" recursion which is easier for reasoning. (splitsplit.{u_1} {α : Type u_1} (a✝ : List α) : List α × List α ysList α).fst + HAdd.hAdd.{u, v, w} {α : Type u} {β : Type v} {γ : outParam (Type w)} [self : HAdd α β γ] (a✝ : α) (a✝¹ : β) : γ`a + b` computes the sum of `a` and `b`. The meaning of this notation is type-dependent. List.lengthList.length.{u_1} {α : Type u_1} (a✝ : List α) : NatThe length of a list: `[].length = 0` and `(a :: l).length = l.length + 1`. This function is overridden in the compiler to `lengthTR`, which uses constant stack space, while leaving this function to use the "naive" recursion which is easier for reasoning. (splitsplit.{u_1} {α : Type u_1} (a✝ : List α) : List α × List α ysList α).snd = Eq.{u_1} {α : Sort u_1} (a✝a✝¹ : α) : PropThe equality relation. It has one introduction rule, `Eq.refl`. We use `a = b` as notation for `Eq a b`. A fundamental property of equality is that it is an equivalence relation. ``` variable (α : Type) (a b c d : α) variable (hab : a = b) (hcb : c = b) (hcd : c = d) example : a = d := Eq.trans (Eq.trans hab (Eq.symm hcb)) hcd ``` Equality is much more than an equivalence relation, however. It has the important property that every assertion respects the equivalence, in the sense that we can substitute equal expressions without changing the truth value. That is, given `h1 : a = b` and `h2 : p a`, we can construct a proof for `p b` using substitution: `Eq.subst h1 h2`. Example: ``` example (α : Type) (a b : α) (p : α → Prop) (h1 : a = b) (h2 : p a) : p b := Eq.subst h1 h2 example (α : Type) (a b : α) (p : α → Prop) (h1 : a = b) (h2 : p a) : p b := h1 ▸ h2 ``` The triangle in the second presentation is a macro built on top of `Eq.subst` and `Eq.symm`, and you can enter it by typing `\t`. For more information: [Equality](https://lean-lang.org/theorem_proving_in_lean4/quantifiers_and_equality.html#equality) List.lengthList.length.{u_1} {α : Type u_1} (a✝ : List α) : NatThe length of a list: `[].length = 0` and `(a :: l).length = l.length + 1`. This function is overridden in the compiler to `lengthTR`, which uses constant stack space, while leaving this function to use the "naive" recursion which is easier for reasoning. ysList α
List.lengthList.length.{u_1} {α : Type u_1} (a✝ : List α) : NatThe length of a list: `[].length = 0` and `(a :: l).length = l.length + 1`. This function is overridden in the compiler to `lengthTR`, which uses constant stack space, while leaving this function to use the "naive" recursion which is easier for reasoning. (splitsplit.{u_1} {α : Type u_1} (a✝ : List α) : List α × List α ysList α).fst + HAdd.hAdd.{u, v, w} {α : Type u} {β : Type v} {γ : outParam (Type w)} [self : HAdd α β γ] (a✝ : α) (a✝¹ : β) : γ`a + b` computes the sum of `a` and `b`. The meaning of this notation is type-dependent. 1 + HAdd.hAdd.{u, v, w} {α : Type u} {β : Type v} {γ : outParam (Type w)} [self : HAdd α β γ] (a✝ : α) (a✝¹ : β) : γ`a + b` computes the sum of `a` and `b`. The meaning of this notation is type-dependent. List.lengthList.length.{u_1} {α : Type u_1} (a✝ : List α) : NatThe length of a list: `[].length = 0` and `(a :: l).length = l.length + 1`. This function is overridden in the compiler to `lengthTR`, which uses constant stack space, while leaving this function to use the "naive" recursion which is easier for reasoning. (splitsplit.{u_1} {α : Type u_1} (a✝ : List α) : List α × List α ysList α).snd + HAdd.hAdd.{u, v, w} {α : Type u} {β : Type v} {γ : outParam (Type w)} [self : HAdd α β γ] (a✝ : α) (a✝¹ : β) : γ`a + b` computes the sum of `a` and `b`. The meaning of this notation is type-dependent. 1 = Eq.{u_1} {α : Sort u_1} (a✝a✝¹ : α) : PropThe equality relation. It has one introduction rule, `Eq.refl`. We use `a = b` as notation for `Eq a b`. A fundamental property of equality is that it is an equivalence relation. ``` variable (α : Type) (a b c d : α) variable (hab : a = b) (hcb : c = b) (hcd : c = d) example : a = d := Eq.trans (Eq.trans hab (Eq.symm hcb)) hcd ``` Equality is much more than an equivalence relation, however. It has the important property that every assertion respects the equivalence, in the sense that we can substitute equal expressions without changing the truth value. That is, given `h1 : a = b` and `h2 : p a`, we can construct a proof for `p b` using substitution: `Eq.subst h1 h2`. Example: ``` example (α : Type) (a b : α) (p : α → Prop) (h1 : a = b) (h2 : p a) : p b := Eq.subst h1 h2 example (α : Type) (a b : α) (p : α → Prop) (h1 : a = b) (h2 : p a) : p b := h1 ▸ h2 ``` The triangle in the second presentation is a macro built on top of `Eq.subst` and `Eq.symm`, and you can enter it by typing `\t`. For more information: [Equality](https://lean-lang.org/theorem_proving_in_lean4/quantifiers_and_equality.html#equality) List.lengthList.length.{u_1} {α : Type u_1} (a✝ : List α) : NatThe length of a list: `[].length = 0` and `(a :: l).length = l.length + 1`. This function is overridden in the compiler to `lengthTR`, which uses constant stack space, while leaving this function to use the "naive" recursion which is easier for reasoning. ysList α + HAdd.hAdd.{u, v, w} {α : Type u} {β : Type v} {γ : outParam (Type w)} [self : HAdd α β γ] (a✝ : α) (a✝¹ : β) : γ`a + b` computes the sum of `a` and `b`. The meaning of this notation is type-dependent. 2
All goals completed! 🐙

Simplifying the goal in arithmetic mode makes it match the assumption this that was introduced by the have tactic.

Tools for Testing

Lean now includes the testing commands #guard_msgs, #check_tactic, and #check_simp from Std. These can be used for lightweight testing of Lean tactics, programs, and metaprograms.

The #guard_msgs command ensures that the messages emitted by the following Lean command are as expected. The expected message is in a documentation comment prior to #guard_msgs.

For example,

❌ Docstring on `#guard_msgs` does not match generated message: info: "4.7.0"#guard_msgs`#guard_msgs` captures the messages generated by another command and checks that they match the contents of the docstring attached to the `#guard_msgs` command. Basic example: ```lean /-- error: unknown identifier 'x' -/ #guard_msgs in example : α := x ``` This checks that there is such an error and then consumes the message entirely. By default, the command intercepts all messages, but there is a way to specify which types of messages to consider. For example, we can select only warnings: ```lean /-- warning: declaration uses 'sorry' -/ #guard_msgs(warning) in example : α := sorry ``` or only errors ```lean #guard_msgs(error) in example : α := sorry ``` In this last example, since the message is not intercepted there is a warning on `sorry`. We can drop the warning completely with ```lean #guard_msgs(error, drop warning) in example : α := sorry ``` Syntax description: ``` #guard_msgs (drop? info|warning|error|all,*)? in cmd ``` If there is no specification, `#guard_msgs` intercepts all messages. Otherwise, if there is one, the specification is considered in left-to-right order, and the first that applies chooses the outcome of the message: - `info`, `warning`, `error`: intercept a message with the given severity level. - `all`: intercept any message (so `#guard_msgs in cmd` and `#guard_msgs (all) in cmd` are equivalent). - `drop info`, `drop warning`, `drop error`: intercept a message with the given severity level and then drop it. These messages are not checked. - `drop all`: intercept a message and drop it. For example, `#guard_msgs (error, drop all) in cmd` means to check warnings and then drop everything else. in`#guard_msgs` captures the messages generated by another command and checks that they match the contents of the docstring attached to the `#guard_msgs` command. Basic example: ```lean /-- error: unknown identifier 'x' -/ #guard_msgs in example : α := x ``` This checks that there is such an error and then consumes the message entirely. By default, the command intercepts all messages, but there is a way to specify which types of messages to consider. For example, we can select only warnings: ```lean /-- warning: declaration uses 'sorry' -/ #guard_msgs(warning) in example : α := sorry ``` or only errors ```lean #guard_msgs(error) in example : α := sorry ``` In this last example, since the message is not intercepted there is a warning on `sorry`. We can drop the warning completely with ```lean #guard_msgs(error, drop warning) in example : α := sorry ``` Syntax description: ``` #guard_msgs (drop? info|warning|error|all,*)? in cmd ``` If there is no specification, `#guard_msgs` intercepts all messages. Otherwise, if there is one, the specification is considered in left-to-right order, and the first that applies chooses the outcome of the message: - `info`, `warning`, `error`: intercept a message with the given severity level. - `all`: intercept any message (so `#guard_msgs in cmd` and `#guard_msgs (all) in cmd` are equivalent). - `drop info`, `drop warning`, `drop error`: intercept a message with the given severity level and then drop it. These messages are not checked. - `drop all`: intercept a message and drop it. For example, `#guard_msgs (error, drop all) in cmd` means to check warnings and then drop everything else. "4.7.0" #eval Lean.versionStringLean.versionString : String

is an error, because there is no expected message provided:

❌ Docstring on `#guard_msgs` does not match generated message:

info: "4.7.0"

Lean provides a quick fix to add or update the message, which results in:

/-- info: "4.7.0" -/ #guard_msgs`#guard_msgs` captures the messages generated by another command and checks that they match the contents of the docstring attached to the `#guard_msgs` command. Basic example: ```lean /-- error: unknown identifier 'x' -/ #guard_msgs in example : α := x ``` This checks that there is such an error and then consumes the message entirely. By default, the command intercepts all messages, but there is a way to specify which types of messages to consider. For example, we can select only warnings: ```lean /-- warning: declaration uses 'sorry' -/ #guard_msgs(warning) in example : α := sorry ``` or only errors ```lean #guard_msgs(error) in example : α := sorry ``` In this last example, since the message is not intercepted there is a warning on `sorry`. We can drop the warning completely with ```lean #guard_msgs(error, drop warning) in example : α := sorry ``` Syntax description: ``` #guard_msgs (drop? info|warning|error|all,*)? in cmd ``` If there is no specification, `#guard_msgs` intercepts all messages. Otherwise, if there is one, the specification is considered in left-to-right order, and the first that applies chooses the outcome of the message: - `info`, `warning`, `error`: intercept a message with the given severity level. - `all`: intercept any message (so `#guard_msgs in cmd` and `#guard_msgs (all) in cmd` are equivalent). - `drop info`, `drop warning`, `drop error`: intercept a message with the given severity level and then drop it. These messages are not checked. - `drop all`: intercept a message and drop it. For example, `#guard_msgs (error, drop all) in cmd` means to check warnings and then drop everything else. in`#guard_msgs` captures the messages generated by another command and checks that they match the contents of the docstring attached to the `#guard_msgs` command. Basic example: ```lean /-- error: unknown identifier 'x' -/ #guard_msgs in example : α := x ``` This checks that there is such an error and then consumes the message entirely. By default, the command intercepts all messages, but there is a way to specify which types of messages to consider. For example, we can select only warnings: ```lean /-- warning: declaration uses 'sorry' -/ #guard_msgs(warning) in example : α := sorry ``` or only errors ```lean #guard_msgs(error) in example : α := sorry ``` In this last example, since the message is not intercepted there is a warning on `sorry`. We can drop the warning completely with ```lean #guard_msgs(error, drop warning) in example : α := sorry ``` Syntax description: ``` #guard_msgs (drop? info|warning|error|all,*)? in cmd ``` If there is no specification, `#guard_msgs` intercepts all messages. Otherwise, if there is one, the specification is considered in left-to-right order, and the first that applies chooses the outcome of the message: - `info`, `warning`, `error`: intercept a message with the given severity level. - `all`: intercept any message (so `#guard_msgs in cmd` and `#guard_msgs (all) in cmd` are equivalent). - `drop info`, `drop warning`, `drop error`: intercept a message with the given severity level and then drop it. These messages are not checked. - `drop all`: intercept a message and drop it. For example, `#guard_msgs (error, drop all) in cmd` means to check warnings and then drop everything else. #eval Lean.versionStringLean.versionString : String

Tactics can be tested using #check_tactic, which takes a starting proof goal, an end goal, and a tactic script, ensuring that the tactics result in the desired end goal when applied to the starting goal. For example:

variable (xNat : NatNat : TypeThe type of natural numbers, starting at zero. It is defined as an inductive type freely generated by "zero is a natural number" and "the successor of a natural number is a natural number". You can prove a theorem `P n` about `n : Nat` by `induction n`, which will expect a proof of the theorem for `P 0`, and a proof of `P (succ i)` assuming a proof of `P i`. The same method also works to define functions by recursion on natural numbers: induction and recursion are two expressions of the same operation from Lean's point of view. ``` open Nat example (n : Nat) : n < succ n := by induction n with | zero => show 0 < 1 decide | succ i ih => -- ih : i < succ i show succ i < succ (succ i) exact Nat.succ_lt_succ ih ``` This type is special-cased by both the kernel and the compiler: * The type of expressions contains "`Nat` literals" as a primitive constructor, and the kernel knows how to reduce zero/succ expressions to nat literals. * If implemented naively, this type would represent a numeral `n` in unary as a linked list with `n` links, which is horribly inefficient. Instead, the runtime itself has a special representation for `Nat` which stores numbers up to 2^63 directly and larger numbers use an arbitrary precision "bignum" library (usually [GMP](https://gmplib.org/)). ) #check_tactic`#check_tactic t ~> r by commands` runs the tactic sequence `commands` on a goal with `t` and sees if the resulting expression has reduced it to `r`. 1 + xNat ~> xNat + 1 by`#check_tactic t ~> r by commands` runs the tactic sequence `commands` on a goal with `t` and sees if the resulting expression has reduced it to `r`.
xNat:NatNat : TypeThe type of natural numbers, starting at zero. It is defined as an inductive type freely generated by "zero is a natural number" and "the successor of a natural number is a natural number". You can prove a theorem `P n` about `n : Nat` by `induction n`, which will expect a proof of the theorem for `P 0`, and a proof of `P (succ i)` assuming a proof of `P i`. The same method also works to define functions by recursion on natural numbers: induction and recursion are two expressions of the same operation from Lean's point of view. ``` open Nat example (n : Nat) : n < succ n := by induction n with | zero => show 0 < 1 decide | succ i ih => -- ih : i < succ i show succ i < succ (succ i) exact Nat.succ_lt_succ ih ``` This type is special-cased by both the kernel and the compiler: * The type of expressions contains "`Nat` literals" as a primitive constructor, and the kernel knows how to reduce zero/succ expressions to nat literals. * If implemented naively, this type would represent a numeral `n` in unary as a linked list with `n` links, which is horribly inefficient. Instead, the runtime itself has a special representation for `Nat` which stores numbers up to 2^63 directly and larger numbers use an arbitrary precision "bignum" library (usually [GMP](https://gmplib.org/)).
Lean.Meta.CheckTactic.CheckGoalTypeLean.Meta.CheckTactic.CheckGoalType.{u} {α : Sort u} (val : α) : PropType used to lift an arbitrary value into a type parameter so it can appear in a proof goal. It is used by the #check_tactic command. (xNat + HAdd.hAdd.{u, v, w} {α : Type u} {β : Type v} {γ : outParam (Type w)} [self : HAdd α β γ] (a✝ : α) (a✝¹ : β) : γ`a + b` computes the sum of `a` and `b`. The meaning of this notation is type-dependent. 1)

#check_simp is just like checkTactic, except it always uses simp as the tactic script.

Proofs about Basic Types

Many, many proofs about basic types have been upstreamed into Lean. This has already made it easier to use Lean without installing extra libraries, lowering the barrier to getting started.

We anticipate even larger benefits going forward. An important aspect of a Lean library is the definition of its simp normal forms. Most libraries include simp lemmas that specify the interactions between the operations provided in the library, guiding the simplifier towards some notion of simpler expressions. A simp normal form is the specification of what simplicity means for a given library. Splitting the development of lemmas about core datatypes between the Lean repository and the Std repository made it much more difficult to coordinate consistent normal forms for simp. While upstreaming these lemmas, we've taken care to ensure that simp is as predictable as possible, with clear normal forms.

Compiler Quality of Life Improvements

Not all improvements in Lean 4.7.0 are upstreamed features from Std.

Improved Completion

Completing symbols is now significantly faster and more robust, especially in contexts where there are a large number of names in scope. In a file with import Mathlib, the performance of various kinds of completions has improved as follows:

  • Completing C: 49000ms -> 1400ms

  • Completing Cat: 14300ms -> 1000ms

  • Completing x. for x : Nat: 3700ms -> 220ms

  • Completing . for an expected type of Nat: 11000ms -> 180ms

Along the way, a number of bugs were fixed as well.

Server Startup

Cross-reference information is now loaded asynchronously, rather than synchronously, when the language server starts. This reduces startup time significantly, at the cost of commands like "find references" returning incomplete results in the first few seconds after opening a file.

Error Messages for decide

The decide tactic uses a DecidableDecidable (p : Prop) : Type`Decidable p` is a data-carrying class that supplies a proof that `p` is either `true` or `false`. It is equivalent to `Bool` (and in fact it has the same code generation as `Bool`) together with a proof that the `Bool` is true iff `p` is. `Decidable` instances are used to infer "computation strategies" for propositions, so that you can have the convenience of writing propositions inside `if` statements and executing them (which actually executes the inferred decidability instance instead of the proposition, which has no code). If a proposition `p` is `Decidable`, then `(by decide : p)` will prove it by evaluating the decidability instance to `isTrue h` and returning `h`. Because `Decidable` carries data, when writing `@[simp]` lemmas which include a `Decidable` instance on the LHS, it is best to use `{_ : Decidable p}` rather than `[Decidable p]` so that non-canonical instances can be found via unification rather than typeclass search. instance to discharge a goal. For example, inequality of natural numbers is decidable, so this proof goes through:

theorem easy_root_.easy : 2 + 2 < 5 : 2 + 2 < 5 :=
2 + HAdd.hAdd.{u, v, w} {α : Type u} {β : Type v} {γ : outParam (Type w)} [self : HAdd α β γ] (a✝ : α) (a✝¹ : β) : γ`a + b` computes the sum of `a` and `b`. The meaning of this notation is type-dependent. 2 < LT.lt.{u} {α : Type u} [self : LT α] (a✝a✝¹ : α) : PropThe less-than relation: `x < y` 5
All goals completed! 🐙

It may not be able to discharge the goal for a variety of reasons:

  • the proposition may be false

  • if the goal contains free variables or metavariables, then the code in the DecidableDecidable (p : Prop) : Type`Decidable p` is a data-carrying class that supplies a proof that `p` is either `true` or `false`. It is equivalent to `Bool` (and in fact it has the same code generation as `Bool`) together with a proof that the `Bool` is true iff `p` is. `Decidable` instances are used to infer "computation strategies" for propositions, so that you can have the convenience of writing propositions inside `if` statements and executing them (which actually executes the inferred decidability instance instead of the proposition, which has no code). If a proposition `p` is `Decidable`, then `(by decide : p)` will prove it by evaluating the decidability instance to `isTrue h` and returning `h`. Because `Decidable` carries data, when writing `@[simp]` lemmas which include a `Decidable` instance on the LHS, it is best to use `{_ : Decidable p}` rather than `[Decidable p]` so that non-canonical instances can be found via unification rather than typeclass search. instance could get stuck, so the tactic fails

  • if the DecidableDecidable (p : Prop) : Type`Decidable p` is a data-carrying class that supplies a proof that `p` is either `true` or `false`. It is equivalent to `Bool` (and in fact it has the same code generation as `Bool`) together with a proof that the `Bool` is true iff `p` is. `Decidable` instances are used to infer "computation strategies" for propositions, so that you can have the convenience of writing propositions inside `if` statements and executing them (which actually executes the inferred decidability instance instead of the proposition, which has no code). If a proposition `p` is `Decidable`, then `(by decide : p)` will prove it by evaluating the decidability instance to `isTrue h` and returning `h`. Because `Decidable` carries data, when writing `@[simp]` lemmas which include a `Decidable` instance on the LHS, it is best to use `{_ : Decidable p}` rather than `[Decidable p]` so that non-canonical instances can be found via unification rather than typeclass search. instance itself is not computable, then it may not return an answer

In prior versions of Lean, the error message made it difficult to know which of these situations had occurred. In Lean 4.7.0, decide now gives a much more useful error message when it is unable to discharge a goal, explicitly stating why it could not complete the proof. If the proposition is false, it says so explicitly:

theorem hard_root_.hard : 2 + 2 < 4 : 2 + 2 < 4 :=
2 + HAdd.hAdd.{u, v, w} {α : Type u} {β : Type v} {γ : outParam (Type w)} [self : HAdd α β γ] (a✝ : α) (a✝¹ : β) : γ`a + b` computes the sum of `a` and `b`. The meaning of this notation is type-dependent. 2 < LT.lt.{u} {α : Type u} [self : LT α] (a✝a✝¹ : α) : PropThe less-than relation: `x < y` 4
2 + HAdd.hAdd.{u, v, w} {α : Type u} {β : Type v} {γ : outParam (Type w)} [self : HAdd α β γ] (a✝ : α) (a✝¹ : β) : γ`a + b` computes the sum of `a` and `b`. The meaning of this notation is type-dependent. 2 < LT.lt.{u} {α : Type u} [self : LT α] (a✝a✝¹ : α) : PropThe less-than relation: `x < y` 4
tactic 'decide' proved that the proposition
  2 + 2 < 4
is false

If it fails because there are variables, the error message is explicit about this:

theorem var_root_.var {n : Nat} : n < n + 2 : nNat < nNat + 2:=
nNat:NatNat : TypeThe type of natural numbers, starting at zero. It is defined as an inductive type freely generated by "zero is a natural number" and "the successor of a natural number is a natural number". You can prove a theorem `P n` about `n : Nat` by `induction n`, which will expect a proof of the theorem for `P 0`, and a proof of `P (succ i)` assuming a proof of `P i`. The same method also works to define functions by recursion on natural numbers: induction and recursion are two expressions of the same operation from Lean's point of view. ``` open Nat example (n : Nat) : n < succ n := by induction n with | zero => show 0 < 1 decide | succ i ih => -- ih : i < succ i show succ i < succ (succ i) exact Nat.succ_lt_succ ih ``` This type is special-cased by both the kernel and the compiler: * The type of expressions contains "`Nat` literals" as a primitive constructor, and the kernel knows how to reduce zero/succ expressions to nat literals. * If implemented naively, this type would represent a numeral `n` in unary as a linked list with `n` links, which is horribly inefficient. Instead, the runtime itself has a special representation for `Nat` which stores numbers up to 2^63 directly and larger numbers use an arbitrary precision "bignum" library (usually [GMP](https://gmplib.org/)).
nNat < LT.lt.{u} {α : Type u} [self : LT α] (a✝a✝¹ : α) : PropThe less-than relation: `x < y` nNat + HAdd.hAdd.{u, v, w} {α : Type u} {β : Type v} {γ : outParam (Type w)} [self : HAdd α β γ] (a✝ : α) (a✝¹ : β) : γ`a + b` computes the sum of `a` and `b`. The meaning of this notation is type-dependent. 2
nNat:NatNat : TypeThe type of natural numbers, starting at zero. It is defined as an inductive type freely generated by "zero is a natural number" and "the successor of a natural number is a natural number". You can prove a theorem `P n` about `n : Nat` by `induction n`, which will expect a proof of the theorem for `P 0`, and a proof of `P (succ i)` assuming a proof of `P i`. The same method also works to define functions by recursion on natural numbers: induction and recursion are two expressions of the same operation from Lean's point of view. ``` open Nat example (n : Nat) : n < succ n := by induction n with | zero => show 0 < 1 decide | succ i ih => -- ih : i < succ i show succ i < succ (succ i) exact Nat.succ_lt_succ ih ``` This type is special-cased by both the kernel and the compiler: * The type of expressions contains "`Nat` literals" as a primitive constructor, and the kernel knows how to reduce zero/succ expressions to nat literals. * If implemented naively, this type would represent a numeral `n` in unary as a linked list with `n` links, which is horribly inefficient. Instead, the runtime itself has a special representation for `Nat` which stores numbers up to 2^63 directly and larger numbers use an arbitrary precision "bignum" library (usually [GMP](https://gmplib.org/)).
nNat < LT.lt.{u} {α : Type u} [self : LT α] (a✝a✝¹ : α) : PropThe less-than relation: `x < y` nNat + HAdd.hAdd.{u, v, w} {α : Type u} {β : Type v} {γ : outParam (Type w)} [self : HAdd α β γ] (a✝ : α) (a✝¹ : β) : γ`a + b` computes the sum of `a` and `b`. The meaning of this notation is type-dependent. 2
expected type must not contain free or meta variables
  n < n + 2

And finally, the use of noncomputable DecidableDecidable (p : Prop) : Type`Decidable p` is a data-carrying class that supplies a proof that `p` is either `true` or `false`. It is equivalent to `Bool` (and in fact it has the same code generation as `Bool`) together with a proof that the `Bool` is true iff `p` is. `Decidable` instances are used to infer "computation strategies" for propositions, so that you can have the convenience of writing propositions inside `if` statements and executing them (which actually executes the inferred decidability instance instead of the proposition, which has no code). If a proposition `p` is `Decidable`, then `(by decide : p)` will prove it by evaluating the decidability instance to `isTrue h` and returning `h`. Because `Decidable` carries data, when writing `@[simp]` lemmas which include a `Decidable` instance on the LHS, it is best to use `{_ : Decidable p}` rather than `[Decidable p]` so that non-canonical instances can be found via unification rather than typeclass search. instances that lead to stuck programs is also indicated explicitly. Classical reasoning allows all propositions to be treated as decidable, but it does not give an algorithm for checking whether they're true or false:

opaque unknownProp_root_.unknownProp : Prop : Prop open scoped Classical in example : unknownPropunknownProp : Prop :=
unknownPropunknownProp : Prop
unknownPropunknownProp : Prop
tactic 'decide' failed for proposition
  unknownProp
since its 'Decidable' instance reduced to
  Classical.choice ⋯
rather than to the 'isTrue' constructor.

Breaking Changes

The rounding behavior of the integer division and modulus infix operators has changed to the Euclidean rounding convention. Users who already use Std will not be affected, as Std was already overriding the rounding behavior to this convention.

The function Lean.withTraceNodeLean.withTraceNode {α : Type} {m : Type → Type} [inst✝ : Monad m] [inst✝¹ : MonadTrace m] [inst✝² : MonadLiftT IO m] [inst✝³ : MonadRef m] [inst✝⁴ : AddMessageContext m] [inst✝⁵ : MonadOptions m] {ε : Type} [always : MonadAlwaysExcept ε m] [inst✝⁶ : MonadLiftT BaseIO m] (cls : Name) (msg : Except ε α → m MessageData) (k : m α) (collapsed : Bool := true) : m α, which is useful for tactic authors and metaprogrammers, now require that they are used in a monad with a MonadAlwaysExceptLean.MonadAlwaysExcept.{u, v} (ε : outParam (Type u)) (m : Type u → Type v) : Type (max (u + 1) v)`MonadExcept` variant that is expected to catch all exceptions of the given type in case the standard instance doesn't. In most circumstances, we want to let runtime exceptions during term elaboration bubble up to the command elaborator (see `Core.tryCatch`). However, in a few cases like building the trace tree, we really need to handle (and then re-throw) every exception lest we end up with a broken tree. εType mType → Type instance. This should be synthesized automatically in most contexts, which are built on EIOEIO (ε a✝ : Type) : Type Lean.ExceptionLean.Exception : TypeException type used in most Lean monads .

The nomatch notation now supports multiple comma-separated terms, and the new nofun introduces assumptions before checking that they are impossible. These are upstreaming the functionality of the match ... with. and fun. notations from Std, but the syntax has changed.