πŸ“₯ Download raw
module Padova2025.ProgrammingBasics.Naturals.Arithmetic where

Arithmetic

open import Padova2025.ProgrammingBasics.Naturals.Base

Beyond the definition of the natural numbers, a canonical next step is to define basic arithmetic. For instance, addition can be defined by pattern matching as follows.

infixl 6 _+_
_+_ : β„• β†’ β„• β†’ β„•
zero   + b = b
succ a + b = succ (a + b)

As in the section on Operators, the underscores in the name of the addition function allow us to use it as an infix operator.

The right-hand side of the second clause in the definition is lifted straight from the Peano axioms. It is mostly a matter of taste whether to do the case split on the first argument, as done above, or instead on the second argument. One way to obtain this definition if one is familiar with high school mathematical laws but not the Peano axioms is as follows:

-- (intuitively, in blackboard mathematics)
-- succ a + b = (1+a) + b = 1 + (a+b) = succ (a + b)

As a sanity check, put some example computation in the hole below (for instance two + two) and verify using C-c C-v that the result is what you would expect:

example-computation : β„•
example-computation = {!!}

Exercise: Halving

Define a function half which divides its input by two, rounding down if required. For instance half four should reduce to two and half three should reduce to one.

half : β„• β†’ β„•
half = {!!}

We could also write the type signature of half as follows:

half : (x : β„•) β†’ β„•

This style is especially useful in case we want the result type, in this case β„•, to depend on the input value x. This syntax is reminiscent of the notation for the universal quantifier used in the beginning of the 20th century: What we now write as β€œβˆ€(xβ€„βˆˆβ€„X). …” used to be written as β€œ(xβ€„βˆˆβ€„X)Β (…)”, as in β€œ(xβ€„βˆˆβ€„β„•)Β (yβ€„βˆˆβ€„β„•)Β ((xβ€…+β€…y)² = xΒ²β€…+β€…2xyβ€…+β€…yΒ²). And indeed, a function associates to every input some output, so mimicking the notation of the universal quantifier makes sense.

Exercise: Predecessor

Implement the predecessor function. For simplicity, let us agree that the predecessor of zero is zero again (instead of introducing negative numbers or error handling).

pred : β„• β†’ β„•
pred = {!!}

Again, we could also write the type signature as pred : (x : β„•) β†’ β„•.

Exercise: Subtraction

Define (cut-off) subtraction. For instance one - one and one - two should both result in zero.

infixl 6 _-_
_-_ : β„• β†’ β„• β†’ β„•
zero   - b      = {!!}
succ a - zero   = {!!}
succ a - succ b = {!!}

Exercise: Multiplication and exponentiation

Define multiplication and exponentiation.

infixl 7 _Β·_
_Β·_ : β„• β†’ β„• β†’ β„•
zero   Β· b = {!!}
succ a Β· b = {!!}

Exercise: Squaring

Define squaring, without using the exponentiation operator introduced below.

infixr 8 _Β²
_Β² : β„• β†’ β„•
_Β² x = {!!}

We could define squaring by reducing to exponentiation, i.e.Β defining x Β² = x ^ 2. This alternative definition would give the same results as the definition envisioned here, and we will be able to state and prove this fact in Agda. However, it is sometimes useful that x Β² is the same as x Β· x by definition instead of by a nontrivial proof. We will touch on this fine point again later.

Exercise: Exponentiation

infixr 8 _^_
_^_ : β„• β†’ β„• β†’ β„•
a ^ zero   = {!!}
a ^ succ b = {!!}

Exercise: Maximum

Define a function max which returns the maximum of two inputs. For instance max one four should be four.

max : β„• β†’ β„• β†’ β„•
max = {!!}