Lean 4.7.0
Lean 4.7.0 has been released! While this release includes the usual collection of qualityoflife 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 outofbox 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 f
(where String → Nat
xString
 1 < fString → Nat
xString
+ 5f
is treated as if it were a variable).String → Nat
xString
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 compiletime bounds checking for array accesses and with recursive functions over numbers.
Array Bounds Checking
In Lean, array lookups are statically boundschecked by default—writing xs
causes Lean to try to prove that Array α
[3]3 < xs
. 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. Array α
.sizeArray.size.{u} {α : Type u} (a : Array α) : Nat
Get the size of an array. This is a cached value, so it is O(1) to access.
xs
were available. In Lean 4.7, Array α
.sizeArray.size.{u} {α : Type u} (a : Array α) : Nat
Get the size of an array. This is a cached value, so it is O(1) to access.
> 18omega
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 manuallyprovided 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://leanlang.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 : Type
The 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 specialcased 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`, "ifthenelse", 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 ifthenelse" `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`, "ifthenelse", 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 ifthenelse" `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`, "ifthenelse", 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 ifthenelse" `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`, "ifthenelse", 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 ifthenelse" `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`, "ifthenelse", 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 ifthenelse" `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`, "ifthenelse", 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 ifthenelse" `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 n
is less than Nat
/ 2n
. Because Nat
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 ondisk 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 recheck 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✝¹ : γ) : Prop
The membership relation `a ∈ s : Prop` where `a : α`, `s : γ`.
xsList α
⊢ fα → β
xα
∈ Membership.mem.{u, v} {α : outParam (Type u)} {γ : Type v} [self : Membership α γ] (a✝ : α) (a✝¹ : γ) : Prop
The 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✝¹ : γ) : Prop
The membership relation `a ∈ s : Prop` where `a : α`, `s : γ`.
xsList α
⊢ fα → β
xα
∈ Membership.mem.{u, v} {α : outParam (Type u)} {γ : Type v} [self : Membership α γ] (a✝ : α) (a✝¹ : γ) : Prop
The 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 mul_lt_root_.mul_lt (x y z : Nat) : x * y < x * z
(xNat
yNat
zNat
: NatNat : Type
The 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 specialcased 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 : Type
The 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 specialcased 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 : Type
The 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 specialcased 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 : Type
The 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 specialcased 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 typedependent.
yNat
< LT.lt.{u} {α : Type u} [self : LT α] (a✝a✝¹ : α) : Prop
The lessthan 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 typedependent.
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 : Type
The 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 specialcased 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 : Type
The 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 specialcased 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 : Type
The 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 specialcased 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 : Type
The 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 specialcased 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 typedependent.
yNat
< LT.lt.{u} {α : Type u} [self : LT α] (a✝a✝¹ : α) : Prop
The lessthan 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 typedependent.
zNat
h
xNat
: NatNat : Type
The 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 specialcased 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 : Type
The 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 specialcased 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 : Type
The 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 specialcased 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✝¹ : α) : Prop
The lessthan relation: `x < y`
zNat
hk
xNat
: NatNat : Type
The 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 specialcased 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 : Type
The 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 specialcased 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 : Type
The 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 specialcased 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 typechecking 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 : Type
The 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 specialcased 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 : Type
The 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 specialcased 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 : Type
The 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 specialcased 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_by?Specify a termination argument for wellfounded 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 : Type
The 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 specialcased 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 : Type
The 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 specialcased 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 : Type
The 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 specialcased 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 wellfounded 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✝ : α) : Nat
The "size" of an element, a natural number which decreases on fields of
each inductive type.
x1Nat
, sizeOfSizeOf.sizeOf.{u} {α : Sort u} [self : SizeOf α] (a✝ : α) : Nat
The "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 generallyuseful 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 casesplits 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
: p1Prop
∧ And (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`.
p2Prop
∧ And (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
⊢ p3Prop
∧ And (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`.
p2Prop
∧ And (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
⊢ p3Prop
∧ And (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`.
p2Prop
∧ And (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
: p1Prop
∨ 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.
p2Prop
∨ 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.
p3Prop
⊢ p3Prop
∨ 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.
p2Prop
∨ 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.
p1Prop
inl
p1Prop
: Prop p2Prop
: Prop p3Prop
: Prop h1p1
: p1Prop
⊢ p3Prop
∨ 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.
p2Prop
∨ 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.
p1Prop
inr.inl
p1Prop
: Prop p2Prop
: Prop p3Prop
: Prop h2p2
: p2Prop
⊢ p3Prop
∨ 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.
p2Prop
∨ 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.
p1Prop
inr.inr
p1Prop
: Prop p2Prop
: Prop p3Prop
: Prop h3p3
: p3Prop
⊢ p3Prop
∨ 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.
p2Prop
∨ 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.
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
: p1Prop
∨ 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.
p2Prop
∧ And (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
∨ 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.
p4Prop
⊢ p4Prop
∨ 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.
p2Prop
∧ And (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
⊢ p4Prop
∨ 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.
p2Prop
∧ And (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
⊢ p4Prop
∨ 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.
p2Prop
∧ And (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
⊢ p4Prop
∨ 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.
p2Prop
∧ And (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 : Type
The 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 specialcased 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 : Type
The 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 specialcased 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✝¹ : α) : Prop
The 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://leanlang.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 typedependent.
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✝¹ : α) : Prop
The 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://leanlang.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 typedependent.
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 typedependent.
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✝¹ : α) : Prop
The 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://leanlang.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 typedependent.
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✝¹ : α) : Prop
The 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://leanlang.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 typedependent.
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 typedependent.
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✝¹ : α) : Prop
The 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://leanlang.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 typedependent.
halfNat
; All goals completed! 🐙
 succNat.succ (n : Nat) : Nat
The 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 : Type
The 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 specialcased 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✝¹ : α) : Prop
The 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://leanlang.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 typedependent.
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✝¹ : α) : Prop
The 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://leanlang.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 typedependent.
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 typedependent.
1
⊢ (∃ half, Nat.succNat.succ (n : Nat) : Nat
The 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✝¹ : α) : Prop
The 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://leanlang.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 typedependent.
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) : Nat
The 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✝¹ : α) : Prop
The 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://leanlang.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 typedependent.
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 typedependent.
1
succ.inl.intro
n'Nat
: NatNat : Type
The 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 specialcased 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 : Type
The 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 specialcased 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✝¹ : α) : Prop
The 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://leanlang.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 typedependent.
halfNat
⊢ (∃ half, Nat.succNat.succ (n : Nat) : Nat
The 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✝¹ : α) : Prop
The 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://leanlang.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 typedependent.
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) : Nat
The 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✝¹ : α) : Prop
The 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://leanlang.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 typedependent.
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 typedependent.
1succ.inr.intro
n'Nat
: NatNat : Type
The 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 specialcased 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 : Type
The 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 specialcased 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✝¹ : α) : Prop
The 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://leanlang.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 typedependent.
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 typedependent.
1
⊢ (∃ half, Nat.succNat.succ (n : Nat) : Nat
The 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✝¹ : α) : Prop
The 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://leanlang.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 typedependent.
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) : Nat
The 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✝¹ : α) : Prop
The 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://leanlang.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 typedependent.
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 typedependent.
1
succ.inl.intro
n'Nat
: NatNat : Type
The 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 specialcased 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 : Type
The 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 specialcased 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✝¹ : α) : Prop
The 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://leanlang.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 typedependent.
halfNat
⊢ (∃ half, Nat.succNat.succ (n : Nat) : Nat
The 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✝¹ : α) : Prop
The 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://leanlang.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 typedependent.
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) : Nat
The 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✝¹ : α) : Prop
The 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://leanlang.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 typedependent.
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 typedependent.
1 succ.inl.intro.h
n'Nat
: NatNat : Type
The 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 specialcased 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 : Type
The 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 specialcased 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✝¹ : α) : Prop
The 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://leanlang.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 typedependent.
halfNat
⊢ ∃ half, Nat.succNat.succ (n : Nat) : Nat
The 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✝¹ : α) : Prop
The 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://leanlang.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 typedependent.
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 typedependent.
1
succ.inl.intro.h
n'Nat
: NatNat : Type
The 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 specialcased 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 : Type
The 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 specialcased 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✝¹ : α) : Prop
The 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://leanlang.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 typedependent.
halfNat
⊢ Nat.succNat.succ (n : Nat) : Nat
The 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✝¹ : α) : Prop
The 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://leanlang.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 typedependent.
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 typedependent.
1
succ.inl.intro.h
n'Nat
: NatNat : Type
The 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 specialcased 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 : Type
The 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 specialcased 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✝¹ : α) : Prop
The 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://leanlang.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 typedependent.
halfNat
⊢ Nat.succNat.succ (n : Nat) : Nat
The 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✝¹ : α) : Prop
The 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://leanlang.org/theorem_proving_in_lean4/quantifiers_and_equality.html#equality)
Nat.succNat.succ (n : Nat) : Nat
The 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 typedependent.
halfNat
)
All goals completed! 🐙
succ.inr.intro
n'Nat
: NatNat : Type
The 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 specialcased 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 : Type
The 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 specialcased 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✝¹ : α) : Prop
The 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://leanlang.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 typedependent.
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 typedependent.
1
⊢ (∃ half, Nat.succNat.succ (n : Nat) : Nat
The 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✝¹ : α) : Prop
The 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://leanlang.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 typedependent.
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) : Nat
The 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✝¹ : α) : Prop
The 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://leanlang.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 typedependent.
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 typedependent.
1 succ.inr.intro.h
n'Nat
: NatNat : Type
The 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 specialcased 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 : Type
The 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 specialcased 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✝¹ : α) : Prop
The 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://leanlang.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 typedependent.
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 typedependent.
1
⊢ ∃ half, Nat.succNat.succ (n : Nat) : Nat
The 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✝¹ : α) : Prop
The 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://leanlang.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 typedependent.
halfNat
succ.inr.intro.h
n'Nat
: NatNat : Type
The 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 specialcased 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 : Type
The 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 specialcased 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✝¹ : α) : Prop
The 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://leanlang.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 typedependent.
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 typedependent.
1
⊢ ∃ half_1, Nat.succNat.succ (n : Nat) : Nat
The 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 typedependent.
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 typedependent.
1) = Eq.{u_1} {α : Sort u_1} (a✝a✝¹ : α) : Prop
The 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://leanlang.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 typedependent.
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 Bounds
:Bounds : 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. Higherpriority 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 : Type
The 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 specialcased 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 : Type
The 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 specialcased 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 Bounds
are already definitionally equal, Bounds : Type
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✝¹ : α) : Prop
The lessthan relation: `x < y`
4 All goals completed! 🐙⟩
def bTwo_root_.bTwo : Bounds
: BoundsBounds : Type
where
lowerNat
:= Nat.succNat.succ (n : Nat) : Nat
The 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 nonproof 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✝¹ : α) : Prop
The 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://leanlang.org/theorem_proving_in_lean4/quantifiers_and_equality.html#equality)
bTwobTwo : Bounds
lower
⊢ bOnebOne : Bounds
.lower = Eq.{u_1} {α : Sort u_1} (a✝a✝¹ : α) : Prop
The 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://leanlang.org/theorem_proving_in_lean4/quantifiers_and_equality.html#equality)
bTwobTwo : Bounds
.lowerupper
⊢ bOnebOne : Bounds
.upper = Eq.{u_1} {α : Sort u_1} (a✝a✝¹ : α) : Prop
The 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://leanlang.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 PaulNicolas 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 α) : Nat
The 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 α) : Nat
The 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 α) : Nat
The 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 α) : Nat
The 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 typedependent.
List.lengthList.length.{u_1} {α : Type u_1} (a✝ : List α) : Nat
The 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✝¹ : α) : Prop
The 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://leanlang.org/theorem_proving_in_lean4/quantifiers_and_equality.html#equality)
List.lengthList.length.{u_1} {α : Type u_1} (a✝ : List α) : Nat
The 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 termmode `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://leanlang.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 termmode `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://leanlang.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 α) : Nat
The 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 typedependent.
List.lengthList.length.{u_1} {α : Type u_1} (a✝ : List α) : Nat
The 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✝¹ : α) : Prop
The 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://leanlang.org/theorem_proving_in_lean4/quantifiers_and_equality.html#equality)
List.lengthList.length.{u_1} {α : Type u_1} (a✝ : List α) : Nat
The 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 α) : Nat
The 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 typedependent.
List.lengthList.length.{u_1} {α : Type u_1} (a✝ : List α) : Nat
The 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✝¹ : α) : Prop
The 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://leanlang.org/theorem_proving_in_lean4/quantifiers_and_equality.html#equality)
List.lengthList.length.{u_1} {α : Type u_1} (a✝ : List α) : Nat
The 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.length
results in a goal that is suitable for List.length.{u_1} {α : Type u_1} (a✝ : List α) : Nat
The 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.
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 α) : Nat
The 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 α) : Nat
The 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 α) : Nat
The 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 α) : Nat
The 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 typedependent.
List.lengthList.length.{u_1} {α : Type u_1} (a✝ : List α) : Nat
The 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✝¹ : α) : Prop
The 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://leanlang.org/theorem_proving_in_lean4/quantifiers_and_equality.html#equality)
List.lengthList.length.{u_1} {α : Type u_1} (a✝ : List α) : Nat
The 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 termmode `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://leanlang.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 termmode `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://leanlang.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 α) : Nat
The 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 typedependent.
List.lengthList.length.{u_1} {α : Type u_1} (a✝ : List α) : Nat
The 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✝¹ : α) : Prop
The 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://leanlang.org/theorem_proving_in_lean4/quantifiers_and_equality.html#equality)
List.lengthList.length.{u_1} {α : Type u_1} (a✝ : List α) : Nat
The 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 α) : Nat
The 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 typedependent.
List.lengthList.length.{u_1} {α : Type u_1} (a✝ : List α) : Nat
The 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✝¹ : α) : Prop
The 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://leanlang.org/theorem_proving_in_lean4/quantifiers_and_equality.html#equality)
List.lengthList.length.{u_1} {α : Type u_1} (a✝ : List α) : Nat
The 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 α) : Nat
The 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 typedependent.
List.lengthList.length.{u_1} {α : Type u_1} (a✝ : List α) : Nat
The 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✝¹ : α) : Prop
The 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://leanlang.org/theorem_proving_in_lean4/quantifiers_and_equality.html#equality)
List.lengthList.length.{u_1} {α : Type u_1} (a✝ : List α) : Nat
The 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 α) : Nat
The 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 typedependent.
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 typedependent.
List.lengthList.length.{u_1} {α : Type u_1} (a✝ : List α) : Nat
The 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 typedependent.
1 = Eq.{u_1} {α : Sort u_1} (a✝a✝¹ : α) : Prop
The 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://leanlang.org/theorem_proving_in_lean4/quantifiers_and_equality.html#equality)
List.lengthList.length.{u_1} {α : Type u_1} (a✝ : List α) : Nat
The 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 typedependent.
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 congrArg
and congrArg.{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://leanlang.org/theorem_proving_in_lean4/quantifiers_and_equality.html#equality)
congrFun
as needed.congrFun.{u, v} {α : Sort u} {β : α → Sort v} {f g : (x : α) → β x} (h : f = g) (a : α) : f a = g a
Congruence in the function part of an application: If `f = g` then `f a = g a`.
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 : Type
The 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 specialcased 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 : Type
The 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 specialcased 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✝¹ : α) : Prop
The 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://leanlang.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 typedependent.
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✝¹ : α) : Prop
The 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://leanlang.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 typedependent.
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 typedependent.
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✝¹ : α) : Prop
The 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://leanlang.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 typedependent.
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✝¹ : α) : Prop
The 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://leanlang.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 typedependent.
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 typedependent.
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✝¹ : α) : Prop
The 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://leanlang.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 typedependent.
halfNat
; All goals completed! 🐙
 succNat.succ (n : Nat) : Nat
The 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 : Type
The 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 specialcased 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✝¹ : α) : Prop
The 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://leanlang.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 typedependent.
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✝¹ : α) : Prop
The 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://leanlang.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 typedependent.
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 typedependent.
1
⊢ (∃ half, Nat.succNat.succ (n : Nat) : Nat
The 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✝¹ : α) : Prop
The 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://leanlang.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 typedependent.
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) : Nat
The 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✝¹ : α) : Prop
The 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://leanlang.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 typedependent.
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 typedependent.
1
succ.inl.intro
n'Nat
: NatNat : Type
The 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 specialcased 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 : Type
The 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 specialcased 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✝¹ : α) : Prop
The 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://leanlang.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 typedependent.
halfNat
⊢ (∃ half, Nat.succNat.succ (n : Nat) : Nat
The 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✝¹ : α) : Prop
The 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://leanlang.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 typedependent.
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) : Nat
The 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✝¹ : α) : Prop
The 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://leanlang.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 typedependent.
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 typedependent.
1succ.inr.intro
n'Nat
: NatNat : Type
The 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 specialcased 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 : Type
The 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 specialcased 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✝¹ : α) : Prop
The 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://leanlang.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 typedependent.
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 typedependent.
1
⊢ (∃ half, Nat.succNat.succ (n : Nat) : Nat
The 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✝¹ : α) : Prop
The 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://leanlang.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 typedependent.
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) : Nat
The 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✝¹ : α) : Prop
The 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://leanlang.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 typedependent.
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 typedependent.
1
succ.inl.intro
n'Nat
: NatNat : Type
The 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 specialcased 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 : Type
The 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 specialcased 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✝¹ : α) : Prop
The 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://leanlang.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 typedependent.
halfNat
⊢ (∃ half, Nat.succNat.succ (n : Nat) : Nat
The 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✝¹ : α) : Prop
The 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://leanlang.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 typedependent.
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) : Nat
The 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✝¹ : α) : Prop
The 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://leanlang.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 typedependent.
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 typedependent.
1 succ.inl.intro.h
n'Nat
: NatNat : Type
The 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 specialcased 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 : Type
The 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 specialcased 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✝¹ : α) : Prop
The 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://leanlang.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 typedependent.
halfNat
⊢ ∃ half, Nat.succNat.succ (n : Nat) : Nat
The 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✝¹ : α) : Prop
The 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://leanlang.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 typedependent.
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 typedependent.
1
All goals completed! 🐙
succ.inr.intro
n'Nat
: NatNat : Type
The 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 specialcased 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 : Type
The 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 specialcased 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✝¹ : α) : Prop
The 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://leanlang.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 typedependent.
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 typedependent.
1
⊢ (∃ half, Nat.succNat.succ (n : Nat) : Nat
The 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✝¹ : α) : Prop
The 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://leanlang.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 typedependent.
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) : Nat
The 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✝¹ : α) : Prop
The 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://leanlang.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 typedependent.
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 typedependent.
1 succ.inr.intro.h
n'Nat
: NatNat : Type
The 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 specialcased 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 : Type
The 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 specialcased 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✝¹ : α) : Prop
The 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://leanlang.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 typedependent.
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 typedependent.
1
⊢ ∃ half, Nat.succNat.succ (n : Nat) : Nat
The 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✝¹ : α) : Prop
The 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://leanlang.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 typedependent.
halfNat
succ.inr.intro.h
n'Nat
: NatNat : Type
The 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 specialcased 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 : Type
The 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 specialcased 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✝¹ : α) : Prop
The 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://leanlang.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 typedependent.
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 typedependent.
1
⊢ ∃ half_1, Nat.succNat.succ (n : Nat) : Nat
The 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 typedependent.
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 typedependent.
1) = Eq.{u_1} {α : Sort u_1} (a✝a✝¹ : α) : Prop
The 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://leanlang.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 typedependent.
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_length
that splitting a list results in two lists whose lengths sum to the original length can use split_length.{u_1} {α : Type u_1} (xs : List α) :
List.length (split xs).fst + List.length (split xs).snd = List.length xs
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 α) : Nat
The 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 α) : Nat
The 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 α) : Nat
The 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 α) : Nat
The 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 typedependent.
List.lengthList.length.{u_1} {α : Type u_1} (a✝ : List α) : Nat
The 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✝¹ : α) : Prop
The 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://leanlang.org/theorem_proving_in_lean4/quantifiers_and_equality.html#equality)
List.lengthList.length.{u_1} {α : Type u_1} (a✝ : List α) : Nat
The 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 termmode `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://leanlang.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 termmode `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://leanlang.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 α) : Nat
The 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 typedependent.
List.lengthList.length.{u_1} {α : Type u_1} (a✝ : List α) : Nat
The 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✝¹ : α) : Prop
The 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://leanlang.org/theorem_proving_in_lean4/quantifiers_and_equality.html#equality)
List.lengthList.length.{u_1} {α : Type u_1} (a✝ : List α) : Nat
The 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 α) : Nat
The 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 typedependent.
List.lengthList.length.{u_1} {α : Type u_1} (a✝ : List α) : Nat
The 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✝¹ : α) : Prop
The 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://leanlang.org/theorem_proving_in_lean4/quantifiers_and_equality.html#equality)
List.lengthList.length.{u_1} {α : Type u_1} (a✝ : List α) : Nat
The 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 α) : Nat
The 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 typedependent.
List.lengthList.length.{u_1} {α : Type u_1} (a✝ : List α) : Nat
The 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✝¹ : α) : Prop
The 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://leanlang.org/theorem_proving_in_lean4/quantifiers_and_equality.html#equality)
List.lengthList.length.{u_1} {α : Type u_1} (a✝ : List α) : Nat
The 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 α) : Nat
The 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 typedependent.
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 typedependent.
List.lengthList.length.{u_1} {α : Type u_1} (a✝ : List α) : Nat
The 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 typedependent.
1 = Eq.{u_1} {α : Sort u_1} (a✝a✝¹ : α) : Prop
The 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://leanlang.org/theorem_proving_in_lean4/quantifiers_and_equality.html#equality)
List.lengthList.length.{u_1} {α : Type u_1} (a✝ : List α) : Nat
The 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 typedependent.
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,
#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? infowarningerrorall,*)? in cmd
```
If there is no specification, `#guard_msgs` intercepts all messages.
Otherwise, if there is one, the specification is considered in lefttoright 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? infowarningerrorall,*)? in cmd
```
If there is no specification, `#guard_msgs` intercepts all messages.
Otherwise, if there is one, the specification is considered in lefttoright 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
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? infowarningerrorall,*)? in cmd
```
If there is no specification, `#guard_msgs` intercepts all messages.
Otherwise, if there is one, the specification is considered in lefttoright 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? infowarningerrorall,*)? in cmd
```
If there is no specification, `#guard_msgs` intercepts all messages.
Otherwise, if there is one, the specification is considered in lefttoright 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 : Type
The 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 specialcased 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 : Type
The 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 specialcased 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 : α) : Prop
Type 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 typedependent.
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.
forx : Nat
: 3700ms > 220ms 
Completing
.
for an expected type ofNat
: 11000ms > 180ms
Along the way, a number of bugs were fixed as well.
Server Startup
Crossreference 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 Decidable
instance to discharge a goal. For example, inequality of natural numbers is decidable, so this proof goes through:Decidable (p : Prop) : Type
`Decidable p` is a datacarrying 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 noncanonical instances can be found via unification rather than
typeclass search.
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 typedependent.
2 < LT.lt.{u} {α : Type u} [self : LT α] (a✝a✝¹ : α) : Prop
The lessthan 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
Decidable
instance could get stuck, so the tactic failsDecidable (p : Prop) : Type
`Decidable p` is a datacarrying 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 noncanonical instances can be found via unification rather than typeclass search.

if the
Decidable
instance itself is not computable, then it may not return an answerDecidable (p : Prop) : Type
`Decidable p` is a datacarrying 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 noncanonical instances can be found via unification rather than typeclass search.
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 typedependent.
2 < LT.lt.{u} {α : Type u} [self : LT α] (a✝a✝¹ : α) : Prop
The lessthan 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 typedependent.
2 < LT.lt.{u} {α : Type u} [self : LT α] (a✝a✝¹ : α) : Prop
The lessthan 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 : Type
The 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 specialcased 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✝¹ : α) : Prop
The lessthan 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 typedependent.
2 nNat
: NatNat : Type
The 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 specialcased 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✝¹ : α) : Prop
The lessthan 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 typedependent.
2
expected type must not contain free or meta variables n < n + 2
And finally, the use of noncomputable Decidable
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:Decidable (p : Prop) : Type
`Decidable p` is a datacarrying 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 noncanonical instances can be found via unification rather than
typeclass search.
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.withTraceNode
, which is useful for tactic authors and metaprogrammers, now require that they are used in a monad with a Lean.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 α
MonadAlwaysExcept
instance. This should be synthesized automatically in most contexts, which are built on Lean.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 rethrow) every exception lest we end up with a broken tree.
εType
mType → Type
EIO
.EIO (ε a✝ : Type) : Type
Lean.ExceptionLean.Exception : Type
Exception type used in most Lean monads
The nomatch
notation now supports multiple commaseparated 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.