module Addition where

open import Data.Nat using ( ; zero ; suc)
open import Relation.Binary.PropositionalEquality
open import Function
open import Relation.Binary.PropositionalEquality.Core
open ≡-Reasoning

_+_ :     
zero + b = b
suc a + b = suc (a + b)

associative+ :  {a b c}  (a + b) + c  a + (b + c)
associative+ {zero} = refl
associative+ {suc a} = cong suc (associative+ {a})

commutative+ :  {a b}  a + b  b + a
commutative+ {zero} = +0
  where
    +0 :  {a}  a  a + zero
    +0 {zero} = refl
    +0 {suc _} = cong suc +0
commutative+ {suc a} = trans (cong suc (commutative+ {a})) +suc
  where
    +suc :  {a b}  suc (a + b)  a + suc b
    +suc {zero} = refl
    +suc {suc _} = cong suc +suc

_*_ :     
zero * b = zero 
suc a * b = b + (a * b)

distributive* :  {a b c}  (a + b) * c  (a * c) + (b * c)
distributive* {zero} = refl
distributive* {suc a} {b} {c} = trans (cong (c +_) (distributive* {a}))
  (sym (associative+ {c} {a * c} {b * c}))

associative* :  {a b c}  a * (b * c)  (a * b) * c
associative* {zero} = refl
associative* {suc a} {b} {c} rewrite distributive* {b} {a * b} {c}
  | sym (associative* {a} {b} {c}) = refl

*0 :  {a}  a * 0  0
*0 {zero} = refl
*0 {suc a} = *0 {a}

*suc :  {a b}  a * suc b  a + (a * b)
*suc {zero} = refl
*suc {suc a} {b} = cong suc (begin
  b + (a * suc b) ≡⟨ cong (b +_) (*suc {a} {b}) 
  b + (a + (a * b)) ≡˘⟨ associative+ {b} {a} {a * b} 
  (b + a) + (a * b) ≡⟨ cong (_+ (a * b)) (commutative+ {b} {a}) 
  (a + b) + (a * b) ≡⟨ associative+ {a} {b} {a * b} 
  a + (b + (a * b)) )

commutative* :  {a b}  a * b  b * a
commutative* {zero} {b} = sym (*0 {b})
commutative* {suc a} {b} = begin
  (b + (a * b)) ≡⟨ cong (b +_) (commutative* {a}) 
  (b + (b * a)) ≡˘⟨ *suc {b} 
  (b * suc a) 

2+5≡7 : 2 + 5  7
2+5≡7 = refl

2+5≡7₁ : 2 + 5  7
2+5≡7₁ = begin 2 + 5 ≡⟨⟩ 1 + 6 ≡⟨⟩ 7  

45*89 : 3 * 45  135
45*89 = begin 3 * 45 ≡⟨⟩ (45 + (2 * 45)) ≡⟨⟩ (45 + (45 + 45)) ≡⟨⟩ 135