Martin Escardo. Notes originally written for the module Advanced Functional Programming of the University of Birmingham, UK.

Type isomorphisms

A function f : A → B is called a bijection if there is a function g : B → A in the opposite direction such that g ∘ f ∼ id and f ∘ g ∼ id. Recall that _∼_ is pointwise equality and that id is the identity function. This means that we can convert back and forth between the types A and B landing at the same element with started with, either from A or from B. In this case, we say that the types A and B are isomorphic, and we write A ≅ B. Bijections are also called type isomorphisms. We can define these concepts in Agda using sum types or records. We will adopt the latter, but we include both definitions for the sake of illustration. Recall that we defined the domain of a function f : A → B to be A and its codomain to be B.

Here we apply the proposition-as-types interpretation of logic to define the concepts:
  is-bijection : {A B : Type}  (A  B)  Type
  is-bijection f = Σ g  (codomain f  domain f) , ((g  f  id) × (f  g  id))

  _≅_ : Type  Type  Type
  A  B = Σ f  (A  B) , is-bijection f
And here we give an equivalent definition which uses records and is usually more convenient in practice and is the one we adopt:
record is-bijection {A B : Type} (f : A  B) : Type where
 constructor
  Inverse
 field
  inverse : B  A
  η       : inverse  f  id
  ε       : f  inverse  id

record _≅_ (A B : Type) : Type where
 constructor
  Isomorphism
 field
  bijection   : A  B
  bijectivity : is-bijection bijection

infix 0 _≅_

The definition with Σ is probably more intuitive, but, as discussed above, the definition with a record is often easier to work with, because we can easily extract the components of the definitions using the names of the fields. It also often allows Agda to infer more types, and to give us more sensible goals in the interactive development of Agda programs and proofs.

Notice that inverse plays the role of g. The reason we use inverse is that then we can use the word inverse to extract the inverse of a bijection. Similarly we use bijection for f, as we can use the word bijection to extract the bijection from a record.

Equivalences in HoTT/UF

In HoTT/UF one uses a refinement of the notion of isomorphism defined above, not discussed in these lecture notes.

Some basic examples

open import binary-type
open import Bool

Bool-𝟚-isomorphism : Bool  𝟚
Bool-𝟚-isomorphism = record { bijection = f ; bijectivity = f-is-bijection }
 where
  f : Bool  𝟚
  f false = 𝟎
  f true  = 𝟏

  g : 𝟚  Bool
  g 𝟎 = false
  g 𝟏 = true

  gf : g  f  id
  gf true  = refl true
  gf false = refl false

  fg : f  g  id
  fg 𝟎 = refl 𝟎
  fg 𝟏 = refl 𝟏

  f-is-bijection : is-bijection f
  f-is-bijection = record { inverse = g ; η = gf ; ε = fg }
But there is also a different isomorphism:
Bool-𝟚-isomorphism' : Bool  𝟚
Bool-𝟚-isomorphism' = record { bijection = f ; bijectivity = f-is-bijection }
 where
  f : Bool  𝟚
  f false = 𝟏
  f true  = 𝟎

  g : 𝟚  Bool
  g 𝟎 = true
  g 𝟏 = false

  gf : g  f  id
  gf true  = refl true
  gf false = refl false

  fg : f  g  id
  fg 𝟎 = refl 𝟎
  fg 𝟏 = refl 𝟏

  f-is-bijection : is-bijection f
  f-is-bijection = record { inverse = g ; η = gf ; ε = fg }

And these are the only two isomorphisms (you could try to prove this in Agda as a rather advanced exercise). More advanced examples are in other files.

Go back to the table of contents