{-# 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))))