Propositional equality is not the only notion of equality that we will use. Isomorphisms play a big role in relating two constructs without relying on strict propositional equality. We start by defining isomorphisms of types
and expand the definition to any preorder relation on a carrier.
Definition
An Isomorphism between two types a,b∈Type is given by two maps to:a→b and from:b→a and proofs that they are inverses of each other.
record (≅) (left, right : Type) where constructor MkIso to : left -> right from : right -> left 0 toFrom : (x : right) -> to (from x) === x 0 fromTo : (x : left) -> from (to x) === x
We establish a couple of properties on isomorphisms that are crucial in using isomorphisms.
Proposition
Isomorphisms are reflexive. That is, given a type a∈Type there is always an isomorphism a≅a.
identity : (0 x : Type) -> x ≅ xidentity x = MkIso id id (\_ => Refl) (\_ => Refl)
Proposition
Isomorphisms are symetric, given an isomorphism a≅b we can obtain the isomorphism b≅a
transIso : {0 x, y, z : Type} -> x ≅ y -> y ≅ z -> x ≅ ztransIso iso1 iso2 = MkIso (iso2.to . iso1.to) (iso1.from . iso2.from) (\v => cong iso2.to (iso1.toFrom (iso2.from v)) `trans` iso2.toFrom v) (\v => trans (cong iso1.from (iso2.fromTo (iso1.to v))) (iso1.fromTo v))
Proposition
Isomorphisms form an equivalence relation.
exportReflexive Type (≅) where reflexive = identity _exportTransitive Type (≅) where transitive = transIsoexportSymmetric Type (≅) where symmetric = symIsoexportEquivalence Type (≅) where
Equalities between isomorphisms
Isomorphisms themselves are interesting structures to study. To prove facts about them we need a notion of equality between isomorphisms. We define it as an equality between the two maps. That definition is enough as we do not need to prove anything about the coherence condtions since, by uniqueness of identity proofs~\ref{def:uip}, they are all the same.
move into its own module Data.Iso.Eq
Definition
Ismorphism equality is given by equality of their to and from maps.
public exportrecord IsoEq (i1, i2 : left ≅ right) where constructor MkIsoEq 0 eqTo : (x : left) -> i1.to x === i2.to x 0 eqFrom : (x : right) -> i1.from x === i2.from x
Proposition
We can convert from Isomorphism equality into propositional equality.
exportsymIsoEq : IsoEq a b -> IsoEq b asymIsoEq (MkIsoEq et tf) = MkIsoEq (\x => sym (et x)) (\x => sym (tf x))
Proposition
Isomorphism equality is transitive.
exporttrans : IsoEq a b -> IsoEq b c -> IsoEq a c
Using isomorphism equality we can start proving facts about isomoprhisms, for example the fact that transitivity of isomorphisms is associative.
Lemma
Transitivity of isomorphisms is associative.
exporttransIsoAssoc : {0 a, b, c, d : Type} -> (f : a ≅ b) -> (g : b ≅ c) -> (h : c ≅ d) -> (f `transIso` (g `transIso` h)) `IsoEq` ((f `transIso` g) `transIso` h)transIsoAssoc f g h = MkIsoEq (\x => Refl) (\_ => Refl)
Lemma
The identity isomorphism is neutral wrt to transitivity of isomorphisms.
exportisoIdRight : (f : a ≅ b) -> transIso f (identity b) `IsoEq` fisoIdRight (MkIso to from toFrom fromTo) = MkIsoEq (\_ => Refl) (\_ => Refl)exportisoIdLeft : (f : a ≅ b) -> transIso (identity a) f `IsoEq` fisoIdLeft (MkIso to from toFrom fromTo) = MkIsoEq (\_ => Refl) (\_ => Refl)
Lemma
There is an isomorphism between any two uninhabited types.
IsoVoid : (u1 : Uninhabited a) => (u2 : Uninhabited b) => a ≅ bIsoVoid = MkIso absurd absurd (\x => absurd x) (\x => absurd x)