{-# OPTIONS --without-K --exact-split --safe #-}
open import Agda.Primitive
infixl 10 _≡_
infixl 50 _+_
infixl 60 _·_
infixl 50 _•_

data _≡_ { : Level} {A : Set } : (x y : A)  Set  where
  refl : {z : A}  z  z

ap : {ℓ₁ ℓ₂ : Level}  {A : Set ℓ₁}  {B : Set ℓ₂}  {x y : A} 
  (f : A  B)  (x  y)  f x  f y
ap f refl = refl

sym : { : Level}  {A : Set }  {x y : A}  x  y  y  x
sym refl = refl

_•_ : { : Level}  {A : Set }  {x y z : A}  x  y  y  z  x  z
refl  refl = refl

data Nat : Set where
  zero : Nat
  suc : Nat  Nat

_+_ : (m n : Nat)  Nat
_+_ zero n = n
_+_ (suc m) n = suc ( m + n )

addition·left·identity : (m : Nat)  zero + m  m
addition·left·identity = λ _  refl

addition·right·identity : (m : Nat)  m + zero  m
addition·right·identity zero = refl
addition·right·identity (suc m) = ap suc (addition·right·identity m)

addition·is·associative : (m n k : Nat)  m + (n + k)  (m + n) + k
addition·is·associative zero n k = refl
addition·is·associative (suc m) n k = ap suc (addition·is·associative m n k)

addition·is·commutative : (m n : Nat)  (m + n  n + m)
addition·is·commutative zero zero = refl
addition·is·commutative (suc m) zero = ap suc (addition·is·commutative m zero)
addition·is·commutative zero (suc n) = ap suc (sym (addition·right·identity n))
addition·is·commutative (suc m) (suc n) = (addition·fact (suc m) n) 
  ap suc (addition·is·commutative (suc m) n) where
    addition·fact : (a b : Nat)  a + suc b  suc (a + b)
    addition·fact zero _ = refl
    addition·fact (suc a) b = ap suc (addition·fact a b)

_·_ : (m n : Nat)  Nat
_·_ zero n = zero
_·_ (suc m) n = n + (m · n)

multiplication·left·zero : (m : Nat)  zero · m  zero
multiplication·left·zero m = refl

multiplication·right·zero : (m : Nat)  m · zero  zero
multiplication·right·zero zero = refl
multiplication·right·zero (suc m) = multiplication·right·zero m

rearrange : (a b c d : Nat)  (a + b) + (c + d)  (a + c) + (b + d)
rearrange zero b c d = (addition·is·associative b c d)  (ap  x  x + d)
  (addition·is·commutative b c))  (sym (addition·is·associative c b d))
rearrange (suc a) b c d = ap suc (rearrange a b c d)

one : Nat
one = suc zero

multiplication·left·one : (m : Nat)  one · m  m
multiplication·left·one zero = multiplication·right·zero one
multiplication·left·one (suc m) = ap suc (addition·right·identity m)

multiplication·right·one : (m : Nat)  m · one  m
multiplication·right·one zero = multiplication·right·zero one
multiplication·right·one (suc m) = (ap  x  one + x)
  (multiplication·right·one m))  (ap suc (addition·left·identity m))

multiplication·is·left·distributive : (m n k : Nat) 
  m · (n + k)  m · n + m · k
multiplication·is·left·distributive zero n k = refl
multiplication·is·left·distributive (suc m) n k = ap  x  (n + k) + x)
  (multiplication·is·left·distributive m n k)  (rearrange n k (m · n) (m · k))

multiplication·is·right·distributive : (m n k : Nat) 
  (m + n) · k  m · k + n · k
multiplication·is·right·distributive zero n k = refl
multiplication·is·right·distributive (suc m) n k = (ap  x  k + x)
  (multiplication·is·right·distributive m n k)) 
  (addition·is·associative k (m · k) (n · k))

multiplication·is·associative : (m n k : Nat)  m · (n · k)  (m · n) · k
multiplication·is·associative zero n k = refl
multiplication·is·associative (suc m) n k = (ap  x  n · k + x)
  (multiplication·is·associative m n k)) 
  (sym (multiplication·is·right·distributive n (m · n) k))

multiplication·is·commutative : (m n : Nat)  m · n  n · m
multiplication·is·commutative zero n = sym (multiplication·right·zero n)
multiplication·is·commutative (suc m) n = (ap  x  n + x)
  (multiplication·is·commutative m n))  (sym (multiplication·fact n m)) where
    multiplication·fact : (a b : Nat)  a · (suc b)  a + a · b
    multiplication·fact zero b = refl
    multiplication·fact (suc a) b = ap suc ((ap  x  b + x)
      (multiplication·fact a b))  (addition·is·associative b a (a · b) ) 
      (ap  x  x + a · b) (addition·is·commutative b a)) 
      (sym (addition·is·associative a b (a · b))))