packages feed

agda2hs-1.3: lib/Haskell/Law/Num/Nat.agda

module Haskell.Law.Num.Nat where

open import Haskell.Prim
open import Haskell.Prim.Num

open import Haskell.Law.Equality
open import Haskell.Law.Num.Def

addNat-suc : ∀ m n → m + suc n ≡ suc (m + n)
addNat-suc zero    n = refl
addNat-suc (suc m) n = cong suc (addNat-suc m n)

addNat-idˡ : ∀ (x : Nat) → 0 + x ≡ x
addNat-idˡ _ = refl

addNat-idʳ : ∀ (x : Nat) → x + 0 ≡ x
addNat-idʳ zero    = refl
addNat-idʳ (suc x) = cong suc (addNat-idʳ x)

addNat-comm : ∀ (x y : Nat) → x + y ≡ y + x
addNat-comm zero    y = sym (addNat-idʳ y)
addNat-comm (suc x) y = begin
  suc (x + y) ≡⟨ cong suc (addNat-comm x y) ⟩
  suc (y + x) ≡⟨ sym (addNat-suc y x) ⟩
  y + suc x   ∎

addNat-assoc : ∀ (x y z : Nat) → (x + y) + z ≡ x + (y + z)
addNat-assoc zero    _ _ = refl
addNat-assoc (suc m) n o = cong suc (addNat-assoc m n o)

mulNat-suc : ∀ (m n : Nat) → m * suc n ≡ m + m * n
mulNat-suc zero    n = refl
mulNat-suc (suc m) n = begin
  suc m * suc n         ≡⟨⟩
  suc n + m * suc n     ≡⟨ cong (suc n +_) (mulNat-suc m n) ⟩
  suc n + (m + m * n)   ≡⟨⟩
  suc (n + (m + m * n)) ≡⟨ cong suc (sym (addNat-assoc n m (m * n))) ⟩
  suc (n + m + m * n)   ≡⟨ cong (λ x → suc (x + m * n)) (addNat-comm n m) ⟩
  suc (m + n + m * n)   ≡⟨ cong suc (addNat-assoc m n (m * n)) ⟩
  suc (m + (n + m * n)) ≡⟨⟩
  suc m + suc m * n     ∎

mulNat-idˡ : ∀ (x : Nat) → 1 * x ≡ x
mulNat-idˡ = addNat-idʳ

mulNat-idʳ : ∀ (x : Nat) → x * 1 ≡ x
mulNat-idʳ zero    = refl
mulNat-idʳ (suc x) = cong suc (mulNat-idʳ x)

mulNat-zeroˡ : ∀ (x : Nat) → 0 * x ≡ 0
mulNat-zeroˡ _ = refl

mulNat-zeroʳ : ∀ (x : Nat) → x * 0 ≡ 0
mulNat-zeroʳ zero    = refl
mulNat-zeroʳ (suc x) = mulNat-zeroʳ x

mulNat-comm : ∀ (x y : Nat) → x * y ≡ y * x
mulNat-comm zero y    = sym (mulNat-zeroʳ y)
mulNat-comm (suc x) y = begin
  suc x * y  ≡⟨⟩
  y + x * y  ≡⟨ cong (y +_) (mulNat-comm x y) ⟩
  y + y * x  ≡⟨ sym (mulNat-suc y x) ⟩
  y * suc x  ∎

mulNat-distributeʳ-addNat : ∀ (x y z : Nat) → (y + z) * x ≡ (y * x) + (z * x)
mulNat-distributeʳ-addNat _ zero    _ = refl
mulNat-distributeʳ-addNat x (suc y) z = begin
  (suc y + z) * x     ≡⟨⟩
  x + (y + z) * x     ≡⟨ cong (x +_) (mulNat-distributeʳ-addNat x y z) ⟩
  x + (y * x + z * x) ≡⟨ sym (addNat-assoc x (y * x) (z * x)) ⟩
  x + y * x + z * x   ≡⟨⟩
  suc y * x + z * x   ∎

mulNat-distributeˡ-addNat : ∀ (x y z : Nat) → x * (y + z) ≡ (x * y) + (x * z)
mulNat-distributeˡ-addNat x y z
  -- This proof transform left distribution to right distribution by using commutativity of *.
  --                                 the initial goal is:  x * (y + z) ≡ (x * y) + (x * z)
  rewrite (mulNat-comm x (y + z)) -- makes or goal become: (y + z) * x ≡ (x * y) + (x * z)
  rewrite (mulNat-comm x y)       -- makes or goal become: (y + z) * x ≡ (y * x) + (x * z)
  rewrite (mulNat-comm x z)       -- makes or goal become: (y + z) * x ≡ (y * x) + (z * x)
  = mulNat-distributeʳ-addNat x y z

mulNat-assoc : ∀ (x y z : Nat) → (x * y) * z ≡ x * (y * z)
mulNat-assoc zero    _ _ = refl
mulNat-assoc (suc x) y z = begin
  (suc x * y) * z     ≡⟨⟩
  (y + x * y) * z     ≡⟨ mulNat-distributeʳ-addNat z y (x * y) ⟩
  y * z + (x * y) * z ≡⟨ cong (y * z +_) (mulNat-assoc x y z) ⟩
  y * z + x * (y * z) ≡⟨⟩
  suc x * (y * z)     ∎

instance
  iLawfulNumNat : IsLawfulNum Nat
  iLawfulNumNat .IsLawfulNum.+-assoc      = addNat-assoc
  iLawfulNumNat .IsLawfulNum.+-comm       = addNat-comm
  iLawfulNumNat .IsLawfulNum.+-idˡ x      = addNat-idˡ x
  iLawfulNumNat .IsLawfulNum.+-idʳ x      = addNat-idʳ x
  iLawfulNumNat .IsLawfulNum.neg-inv zero = refl -- inline this proof because it has not much use anyway I guess?
  iLawfulNumNat .IsLawfulNum.*-assoc      = mulNat-assoc
  iLawfulNumNat .IsLawfulNum.*-idˡ x      = mulNat-idˡ x
  iLawfulNumNat .IsLawfulNum.*-idʳ x      = mulNat-idʳ x
  iLawfulNumNat .IsLawfulNum.distributeˡ  = mulNat-distributeˡ-addNat
  iLawfulNumNat .IsLawfulNum.distributeʳ  = mulNat-distributeʳ-addNat