agda2hs-1.4: lib/base/Haskell/Law/Num/Def.agda
module Haskell.Law.Num.Def where
open import Haskell.Prim
open import Haskell.Prim.Num
open import Haskell.Prim.Integer
record IsLawfulNum (a : Type) ⦃ iNum : Num a ⦄ : Type₁ where
field
+-assoc : ∀ (x y z : a) → (x + y) + z ≡ x + (y + z)
+-comm : ∀ (x y : a) → x + y ≡ y + x
+-idˡ : ∀ (x : a) {{@0 _ : Num.FromIntegerOK iNum 0}}
→ fromInteger 0 + x ≡ x
+-idʳ : ∀ (x : a) {{@0 _ : Num.FromIntegerOK iNum 0}}
→ x + fromInteger 0 ≡ x
neg-inv : ∀ (x : a) {{@0 _ : Num.FromIntegerOK iNum 0}} {{@0 _ : Num.NegateOK iNum x}}
→ x + negate x ≡ fromInteger 0
*-assoc : ∀ (x y z : a) → (x * y) * z ≡ x * (y * z)
*-idˡ : ∀ (x : a) {{@0 _ : Num.FromIntegerOK iNum 1}}
→ fromInteger 1 * x ≡ x
*-idʳ : ∀ (x : a) {{@0 _ : Num.FromIntegerOK iNum 1}}
→ x * fromInteger 1 ≡ x
distributeˡ : ∀ (x y z : a) → x * (y + z) ≡ (x * y) + (x * z)
distributeʳ : ∀ (x y z : a) → (y + z) * x ≡ (y * x) + (z * x)
-- We are currently missing the following because toInteger is missing in our Prelude.
-- "if the type also implements Integral, then fromInteger is a left inverse for toInteger, i.e. fromInteger (toInteger i) == i"
open IsLawfulNum ⦃ ... ⦄ public
open import Haskell.Law.Equality
open import Haskell.Law.Function
{-|
A number homomorphism establishes a homomorphism from one Num type a to another one b.
In particular, zero and one are mapped to zero and one in the other Num type,
and addition, multiplication, and negation are homorphic.
-}
record NumHomomorphism (a b : Type) ⦃ iNuma : Num a ⦄ ⦃ iNumb : Num b ⦄ (φ : a → b) : Type where
0ᵃ = Num.fromInteger iNuma (pos 0)
0ᵇ = Num.fromInteger iNumb (pos 0)
1ᵃ = Num.fromInteger iNuma (pos 1)
1ᵇ = Num.fromInteger iNumb (pos 1)
field
+-hom : Homomorphism₂ _+_ _+_ φ
*-hom : Homomorphism₂ _*_ _*_ φ
⦃ minus-ok ⦄ : ∀ {x y : a} → ⦃ MinusOK x y ⦄ → MinusOK (φ x) (φ y)
⦃ negate-ok ⦄ : ∀ {x : a} → ⦃ NegateOK x ⦄ → NegateOK (φ x)
⦃ fromInteger-ok ⦄ : ∀ {i : Integer} → ⦃ Num.FromIntegerOK iNuma i ⦄ → Num.FromIntegerOK iNumb i
0-hom : ⦃ @0 _ : Num.FromIntegerOK iNuma (pos 0) ⦄ → φ 0ᵃ ≡ 0ᵇ
1-hom : ⦃ @0 _ : Num.FromIntegerOK iNuma (pos 1) ⦄ → φ 1ᵃ ≡ 1ᵇ
negate-hom : ∀ (x : a) → ⦃ @0 _ : Num.NegateOK iNuma x ⦄ → φ (negate x) ≡ negate (φ x) --Homomorphism₁ inlined for type instances
{-|
A number embedding is an invertible number homomorphism.
-}
record NumEmbedding (a b : Type) ⦃ iNuma : Num a ⦄ ⦃ iNumb : Num b ⦄ (φ : a → b) (φ⁻¹ : b → a) : Type where
field
hom : NumHomomorphism a b φ
embed : φ⁻¹ ∘ φ ≗ id
open NumHomomorphism hom
+-Embedding₂ : Embedding₂ _+_ _+_ φ φ⁻¹
Embedding₂.hom +-Embedding₂ = +-hom
Embedding₂.embed +-Embedding₂ = embed
*-Embedding₂ : Embedding₂ _*_ _*_ φ φ⁻¹
Embedding₂.hom *-Embedding₂ = *-hom
Embedding₂.embed *-Embedding₂ = embed
+-MonoidEmbedding₂ : ⦃ @0 _ : Num.FromIntegerOK iNuma (pos 0) ⦄ → MonoidEmbedding₂ _+_ _+_ φ φ⁻¹ 0ᵃ 0ᵇ
MonoidEmbedding₂.embedding +-MonoidEmbedding₂ = +-Embedding₂
MonoidEmbedding₂.0-hom +-MonoidEmbedding₂ = 0-hom
*-MonoidEmbedding₂ : ⦃ @0 _ : Num.FromIntegerOK iNuma (pos 1) ⦄ → MonoidEmbedding₂ _*_ _*_ φ φ⁻¹ 1ᵃ 1ᵇ
MonoidEmbedding₂.embedding *-MonoidEmbedding₂ = *-Embedding₂
MonoidEmbedding₂.0-hom *-MonoidEmbedding₂ = 1-hom
{-|
Given an embedding from one number type a onto another one b,
we can conclude that b satisfies the laws of Num if a satisfies the
laws of Num.
-}
map-IsLawfulNum : ∀ {a b : Type} ⦃ iNuma : Num a ⦄ ⦃ iNumb : Num b ⦄
→ (a2b : a → b) (b2a : b → a)
→ NumEmbedding a b a2b b2a
→ IsLawfulNum b
-----------------------
→ IsLawfulNum a
map-IsLawfulNum {a} {b} {{numa}} {{numb}} f g proj lawb =
record
{ +-assoc = map-assoc _+ᵃ_ _+ᵇ_ f g +-Embedding₂ (+-assoc lawb)
; +-comm = map-comm _+ᵃ_ _+ᵇ_ f g +-Embedding₂ (+-comm lawb)
; +-idˡ = λ x → map-idˡ _+ᵃ_ _+ᵇ_ f g 0ᵃ 0ᵇ +-MonoidEmbedding₂ (λ y → +-idˡ lawb y) x
; +-idʳ = λ x → map-idʳ _+ᵃ_ _+ᵇ_ f g 0ᵃ 0ᵇ +-MonoidEmbedding₂ (λ y → +-idʳ lawb y) x
; neg-inv = map-neg-inv
; *-assoc = map-assoc _*ᵃ_ _*ᵇ_ f g *-Embedding₂ (*-assoc lawb)
; *-idˡ = λ x → map-idˡ _*ᵃ_ _*ᵇ_ f g 1ᵃ 1ᵇ *-MonoidEmbedding₂ (λ y → *-idˡ lawb y) x
; *-idʳ = λ x → map-idʳ _*ᵃ_ _*ᵇ_ f g 1ᵃ 1ᵇ *-MonoidEmbedding₂ (λ y → *-idʳ lawb y) x
; distributeˡ = map-distributeˡ _+ᵃ_ _+ᵇ_ _*ᵃ_ _*ᵇ_ f g embed +-hom *-hom (distributeˡ lawb)
; distributeʳ = map-distributeʳ _+ᵃ_ _+ᵇ_ _*ᵃ_ _*ᵇ_ f g embed +-hom *-hom (distributeʳ lawb)
}
where
open NumEmbedding proj
open NumHomomorphism hom
open IsLawfulNum lawb
open Num numa renaming (_+_ to _+ᵃ_; _*_ to _*ᵃ_; negate to negateᵃ)
open Num numb renaming (_+_ to _+ᵇ_; _*_ to _*ᵇ_; negate to negateᵇ)
map-neg-inv : ∀ (x : a) ⦃ @0 _ : Num.FromIntegerOK numa (pos 0) ⦄ ⦃ @0 _ : Num.NegateOK numa x ⦄
→ x +ᵃ negateᵃ x ≡ 0ᵃ
map-neg-inv x =
x +ᵃ negateᵃ x ≡˘⟨ embed (x +ᵃ negateᵃ x) ⟩
g (f (x +ᵃ negateᵃ x)) ≡⟨ cong g (+-hom x (negateᵃ x)) ⟩
g (f x +ᵇ f (negateᵃ x)) ≡⟨ cong g (cong (f x +ᵇ_) (negate-hom x)) ⟩
g (f x +ᵇ negateᵇ (f x)) ≡⟨ cong g (neg-inv lawb (f x)) ⟩
g 0ᵇ ≡˘⟨ cong g 0-hom ⟩
g (f 0ᵃ) ≡⟨ embed 0ᵃ ⟩
0ᵃ ∎