# Examples of Proofs #

We see our first proofs, most of which involve the `≤`

relation on natural numbers.

We will see that the natural numbers are "defined" in terms of the `zero`

and `succ`

constructors.

Analogous to this, (modulo renaming) the `≤`

relation is defined in terms of the `le_refl`

and `le_step`

constructors.

`Nat.le : ℕ → ℕ → Prop`

`Nat.le_refl : ∀ n : ℕ, n ≤ n`

`Nat.le_step : ∀ {n m : ℕ}, n ≤ m → n ≤ Nat.succ m`

However, we will first focus on a simpler relation.

### Example: a proof by reflexivity of equality #

Our first example is simpler: just a proof of equality. Note that a proof of a theorem in lean is very similar, both conceptually and syntactically, to a definition.

In a definition, we give a name, a type and a value (though sometimes the type is inferred so can be omitted). In a theorem, we give a name, a statement and a proof. The statement is essentially a type, and the proof is a value of that type.

Technically a statement is a proposition which is a special sort of type as we see below, but in these examples it is best to think of it as just a type.

We look more closely at the right hand side, i.e., the *proof*. Below is the description in Lean of `rfl`

, which corresponds to *reflexivity of equality*, i.e., the fact that any term is equal to itself:

`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.

To clarify what is meant by *implicit* and *explicit* parameters, we look at the types of `rfl`

and `Eq.refl`

. Both these represent the statement that if `α`

is a type and `a : α`

is a term of type `α`

then `a = a`

.

```
#check rfl -- rfl.{u} {α : Sort u} {a : α} : a = a
#check Eq.refl -- Eq.refl.{u_1} {α : Sort u_1} (a : α) : a = a
```

Notice that in `rfl`

*both* the arguments `α`

and `a`

are in braces while in `Eq.refl`

the argument `α`

is in braces while `a`

in in parenthesis. When calling a function, the arguments in parenthesis are to be specified, while those in braces are to be *inferred* (if possible).

If we prepend `@`

to a function name then all arguments become explicit. Conversely we can ask Lean to infer arguments by using `_`

. The following examples of similar proofs should clarify these.

```
/- argument `a` given explicitly -/
example : 2 = 2 := Eq.refl 2
/- notation `@` used and both `α` and `a` are given explicitly-/
example : 3 = 3 := @Eq.refl ℕ 3
/- the argument `a` is inferred-/
example : 1 + 2 = 3 := Eq.refl _
/- notation `@` used but `α` is inferred-/
example : 3 = 3 := @Eq.refl _ 3
```

### Incorrect proofs #

Of course the right hand side may not be a proof of the statement in the left hand side. As mentioned above, this is equivalent to the term on the right-hand side having the *type* specified in the left hand side.

For example, consdier the following (incorrect) proof.

```
theorem wrong : 1 + 2 = 2 := rfl
```

We get the following error message:

```
type mismatch
rfl
has type
1 + 2 = 1 + 2 : Prop
but is expected to have type
1 + 2 = 2 : Prop
```

This is because Lean inferred that `a`

is `1 + 2`

(and `α`

is `ℕ`

) and deduced that the type of the right hand side is `1 + 2 = 1 + 2`

. This is not equal to the type specified in the left hand side, `1 + 2 = 2`

.

We get a different type of error if the statement we are trying to prove is not an equality. For example, consider the following (incorrect) proof.

```
example : 1 ≤ 2 := rfl
```

Here Lean is not able to infer `a`

(or even `α`

) and so we get the following error message:

```
type mismatch
rfl
has type
?m.690 = ?m.690 : Prop
but is expected to have type
1 ≤ 2 : Prop
```

All that Lean knows about `rfl`

is that it is a proof that `a = a`

, but the statement is not an equality. So Lean assign a *metavariable* `?m.690`

to `a`

and cannot *solve* for the metavariable, giving an error as above.

### Proofs versus Definitions; Sorts and Types #

To clarify the similarities and differences between a definition and a theorem, as well as sorts and types, we look at the following example.

As we have remarked, this is formally very similar to the proof of a theorem. To see the differences, we see some associated types:

```
#check 1 = 1 -- 1 = 1 : Prop
#check ℕ -- ℕ : Type
/- The universe of propositions. Prop ≡ Sort 0-/
#check Prop -- Prop : Type
/- A type universe. Type ≡ Type 0, Type u ≡ Sort (u + 1)-/
#check Type -- Type : Type 1
```

The main difference between the two cases is that the type of a theorem is a *proposition*, which is a special *type* (i.e., a type in `Prop`

). The type of `Prop`

is `Type`

, which is a type in the next universe up and is the type of `ℕ`

. The universes form so called *Sorts*, with all but the first being *Types*.

In other closely related foundational systems (such as *Homotopy Type Theory*), this distinction is not present and all uninverses are *Types*. In Lean *propositions*, i.e., elements of `Prop`

(such as `1 = 1`

) have a special property that two terms (i.e., proofs) of a proposition are equal by definition.

Propositions are taken to be at "Types at level -1", i.e., "Sorts at level 0". This makes it convenient to exclude propositions in some cases where it is necessary to do so (as we will see later).