# Subtraction: example of intertwined proofs and definitions. #

The difference of natural numbers is not a natural number. We see three ways of overcoming this problem, which illustrate various important concepts in Lean.

The first two are in this module while the third is in a sequel. The first two are in fact available in functional programming langauges such as `scala`

and `Haskell`

.

To begin with, we see how Lean deals with subtraction on `ℕ`

.

```
#eval 4 - 3 -- 1
#eval 3 - 4 -- 0
```

The first example is as expected, but the second may be surprising. According to the documentation of Lean 4, `Nat.sub`

is:

(Truncated) subtraction of natural numbers. Because natural numbers are not closed under subtraction, we define

`m - n`

to be 0 when`n < m`

.

## Subtraction with panic #

Our first remedy is to define subtraction as Lean does but with an error message when the result is incorrect.

```
def Nat.sub! (m n: Nat) :=
match m, n with
| m, 0 => m
| m + 1, n + 1 => Nat.sub! m n
| 0, _ + 1 => panic! "cannot subtract a larger number from a smaller one"
#eval Nat.sub! 4 3 -- 1
#eval Nat.sub! 3 4 -- 0 (but with an error message)
```

A brief digression: Lean 4 lets us easily introduce new notation for our variant of subtraction.

```
infix:64 "-!" => Nat.sub!
```

infix notation for subtraction with panic.

## Equations

- «term_-!_» = Lean.ParserDescr.trailingNode `term_-!_ 64 65 (Lean.ParserDescr.binary `andthen (Lean.ParserDescr.symbol "-!") (Lean.ParserDescr.cat `term 65))

## More on panicking #

The intriguing fact about the illegal subtraction is that, while it gave an error, it still had a value. Indeed, we see more of the underlying phenomenon in the following examples.

```
def panicNat : ℕ := panic! "I like to panic"
#check panicNat -- ℕ
-- #eval panicNat -- 0 (with error)
```

Note that `panicNat`

had a type, and the computation of the type did not give an error. Hence for logical consistency, the value of `panicNat`

must be a term of type `ℕ`

.

Indeed, if we try to make an analogous definition for `Empty`

we get an error.

```
def badPanic : Empty :=
panic! "sometimes we are not even allowed to panic"
```

gives the error message:

```
failed to synthesize instance
Inhabited Empty
```

Indeed the empty type has no inhabitants so allowing a definition of `badPanic`

would be a contradiction.

## Default values and typeclasses #

The value returned when panicing is the `default`

value of the type. Not every type has a default value. For example, the `Empty`

type has no default value.

Default values can be *synthesized* from other default values by so called *typeclass* inference. First we see some examples of default values.

```
```

```
#eval defaultNat -- 0
```

As we have seen earlier, the default value of `ℕ`

is `0`

.

As we saw in the case of panic, the default value of `Empty`

is not defined. The following gives an error message.

```
def defaultEmpty : Empty := default
```

A more interesting example is the default value of a product type.

```
#eval default₁ -- (0, 0)
```

This is inferred from the default values of the components.

### Typeclasses #

We sketch the basic ideas of typeclasses and how they are used here. The `default`

value of a type `α`

is based on `Inhabited α`

.

Some more examples of typeclass inference.

```
#reduce default₂ -- (Nat.zero, "", fun x => Nat.zero)
#reduce default₃ -- (Nat.zero, fun x => Nat.zero, fun a => False.rec (fun x => Empty) (_ : False))
```

In the first example, we see that default functions are inferred if the codomains are inhabited, with a constant function used as a default.

Lean has inferred a default function from `Empty`

to `Empty`

by using the default function from `Empty`

to `False`

. To illustrate introducing new defaults we introduce a new type `MyEmpty`

which is also an empty type.

An instance of `Inhabited`

corresponding to the identity function from any type to itself.

## Equations

- instInhabitedForAll_3 α = { default := id }

We see this picked up in the following construction. Note that defining a default for `MyEmpty`

gives an error.

```
#reduce default₄ -- (Nat.zero, fun x => Nat.zero, fun x a => a)
```

The following example shows the effect of priorities of instances.

```
#reduce default₆ -- (Nat.zero, fun x => Nat.zero, fun x a => a)
```

Observe that the second component is the constant function `fun x => Nat.zero`

and not the identity function `id`

.

## Second rectification: `Option`

#

The second choice is to essentially return values only when they are valid, by wrapping them in an `Option`

.

## Equations

- «term_-?_» = Lean.ParserDescr.trailingNode `term_-?_ 64 65 (Lean.ParserDescr.binary `andthen (Lean.ParserDescr.symbol "-?") (Lean.ParserDescr.cat `term 65))

Some examples of subtraction returning option types.

```
#eval 4 -? 3 -- some 1
#eval 3 -? 4 -- none
```

If we return option types we need to be able to handle them. We illustrate this by defining a function that returns the double of the difference if it is defined.

```
def Nat.doubleSub? (m n : ℕ) : Option ℕ :=
(m -? n).map (· * 2)
#eval Nat.doubleSub? 5 3 -- some 4
#eval Nat.doubleSub? 5 32 -- none
```

Optionally return `(m - n) * 2`

if `m ≥ n`

.

## Equations

- Nat.doubleSub? m n = Option.map (fun x => x * 2) (m-?n)

A convenient way to handle option types is to use the `do`

notation.

```
def Nat.tripleSub? (m n : ℕ) : Option ℕ :=
do
let d ← m -? n
return d * 3
#eval Nat.tripleSub? 5 3 -- some 6
```

The `do`

notation is even more convenient when we compose option valued functions.

```
def Nat.sub_sub? (a b c : ℕ) : Option ℕ :=
do
let d₁ ← a -? b
let d₂ ← d₁ -? c
return d₂
```