This is cumbersome and prone to mistakes. Instead we use pattern matching. A function $A -> C$ is completely specified if it's specified on the *canonical elements* of $A$.
$ isZero& : Nat -> Bool \
isZero& zero defeq tru \
isZero& suc (n) defeq fls \
$
=== Pairs
#let pair = $sans("pair")$
#typeIntroTable(
[If $A$ and $B$ are types, then $A times B$ is a type],
[If $a : A$ and $b : B$, then $pair(a, b) : A times B$],
[If $C$ is a type, and $p : A -> B -> C$ and $t : A times B$, then $rec_times (A, B, C, p, t) : C$],
[...],
)
#let fst = $sans("fst")$
#let snd = $sans("snd")$
#let swap = $sans("swap")$
#let assoc = $sans("assoc")$
*Exercise.* Define $snd : A times B -> A$ and $snd : A times B -> B$.
*Exercise.* Given types $A$ and $B$, write a function $swap$ of type $A times B -> B times A$.
*Exercise.* What is the type of $swap @ pair (tt , fls)$?
*Exercise.* Write a function $assoc$ of type $(A times B) times C -> A times (B times C)$
=== Type dependency
In particular: dependent type $B$ over $A$. (read "family $B$ of types indexed by $A$")
Example: type of vectors.
$ n : Nat tack.r Vect(n) $
=== Universes
#let Type = $sans("Type")$
There is a type $Type$. Its elements are types ($A : Type$). The dependent function $x : A tack.r B$ can be considered a function $lambda x . B : A -> Type$.
What is the type of $Type$? $Type$ is in an indexed hierarchy to avoid type-in-type paradox. We usually omit the index: $Type_i : Type_(i + 1)$
=== Dependent functions $product_(x : A) B$
#typeIntroTable(
[If $A$ is a type, and $B$ is a type family indexed by $A$, then there is a type $product_(x : A) B$],
[If $(x : A) tack.r b : B$, then $lambda (x : A) . b : product_(x : A) B$],
[If $f : product_(x : A) B$ and $a : A$, then $f(a) : subst(x, a, B)$],
[$(lambda (x : A) . b) ( a) defeq subst(x, a, b)$
- The case $A -> B$ is a special case of the dependent function, where $B$ doesn't depend on $x : A$],
)
=== Dependent pairs $Sigma_(x : A) B$
#typeIntroTable(
[If $x : A tack.r B$, then there is a type $Sigma_(x : A) B$],
[If $a : A$ and $b : B(a)$, then $pair (a, b) : Sigma_(x : A) B$],
[...],
[...
- The case $A times B$ is a special case of the dependent function, where $B$ doesn't depend on $x : A$],
)
=== Identity type
#let Id = $sans("Id")$
#let refl = $sans("refl")$
#let propeq = $=$
#typeIntroTable(
[If $a : A$ and $b : A$, then $Id_A (a, b)$ is a type],
[If $a : A$, then $refl(a) : Id_A (a, a)$],
[
- If $(x, y : A), (p : Id_A (x, y)) tack.r C (x, y, p)$
- and $(x : A) tack.r t(x) : C(x, x, refl(x))$
- then $(x, y : A), (p : Id_A (x, y)) tack.r ind_Id (t; x, y, p) : C(x, y, p)$],
[...],
)
- (There are dependent versions of each of the previous elimination rules that resulted in $C$)
- $ind$ "induction" is used more when the $C$ is dependent, while $rec$ is better for non-dependent $C$'s.
For example, to define:
#let sym = $sans("sym")$
$ sym : product_(x, y : A) Id(x, y) -> Id(y, x) $
it suffices to just specify its image on $(x, x, refl)$
#prooftree(
axiom($x : A tack.r refl(x) : Id(x, x)$),
rule($(x, y : A) , (p : Id(x, y)) tack.r Id(y, x)$),
rule($x, y : A tack.r Id(x, y) -> Id(y, x)$),
rule($sym : product_(x, y : A) Id(x, y) -> Id(y, x)$)
)
So $sym(x, x, refl(x)) :defeq refl(x)$
#let transport = $sans("transport")$
*Exercise.* Define $transport^B : product_(x, y : A) Id(x, y) -> B(x) -> B(y)$.
*Exercise: swap is involutive.* Given types $A$ and $B$, write a function $product_(t : A times B) Id(swap(swap(t)), t)$
=== Disjoint sum
#let inl = $sans("inl")$
#let inr = $sans("inr")$
#typeIntroTable(
[If $A$ and $B$ are types, then $A + B$ is a type],
[
- If $a : A$, then $inl(a) : A + B$
- If $b : B$, then $inr(b) : A + B$
],
[If $f : A -> C$ and $g : B ->C $ then $rec_+ (C, f, g) : A + B -> C$],
[$x : A tack.r B(x)$], [fibration $B -> A$ with fibers $B(x)$],
[$sum_(x : A) B(x)$], [total space of fibration $B -> A$],
[$product_(x : A) B(x)$], [space of sections of fibration $B -> A$],
)
Question: more intuition on fibration?
- Fibration is something that has the transport property. A fibration is a _map_ in the category (i.e $B -> A$).
#image("fibration.jpeg", height: 3in)
Path lifting can be done over fibers in a fibration such as $B :defeq sum_(a : A) B(a)$
=== Contractible types
#let isContr = $sans("isContr")$
*Definition (contractible).* A type $A$ is contractible if: $ isContr(A) :defeq sum_(x : A) product_(y : A) y pathto x $
In homotopy theory, you can contract a space into a single point. This is also called a *singleton*. The specified point $a$ is called the "center" of contraction, and there are paths from any other $y : A$ to $x$.
Question: do you have to give the point?
- In constructive logic, you must explicitly give the point that it is contracted to, cannot just prove with contradiction.
=== Equivalence
#let isequiv = $sans("isequiv")$
*Definition (equivalence).* A map $f : A -> B$ is an *equivalence* if it has contractible fibers.
$ isequiv(f) :defeq product_(b : B) isContr(sum_(a : A) f(a) pathto b) $
Fix $b$, the sigma is the preimage of the point $b$. For all $b$, all preimages are contractible.
#let eqv = $tilde.eq$
$ A eqv B :defeq sum_(f : A -> B) isequiv(f) $
There are also other definitions of equivalence.
*Exercise.* Show that 1 is contractible.
*Exercise.* Let $A$ be a contractible type. Construct an equivalence $A eqv 1$
For paths between pairs, in the dependent version, we have
$ ((a, b) pathto (a' , b')) eqv sum_(p : a pathto a') transport^B (p, b) pathto b' $
This is required because $b : B(a)$ but $b' : B(a')$, and we can't write paths between different types.
So instead, we use transport to get back into the correct type: $transport^B (p, b) : B(a')$
=== Path types of identity types
Cannot show uniqueness of identity proofs (UIP): $ product_(a, b: A) product_(p, q : a pathto b) p pathto q $
(Lean assumes UIP)
=== Path types of the universe
#let idtoequiv = $sans("idtoequiv")$
$ idtoequiv : product_(A, B : Type) (A pathto B) -> (A eqv B) $
*Definition (univalence).* $idtoequiv$ is an equivalence.
- Question: What is the benefit of UIP over univalence?
- UIP gives set theory
- Question: what if you had a path between $A pathto B$ and $A eqv B$?
- You can use univalence to get a path. But we shouldn't assume an equality without first using $idtoequiv$.
=== Propositional truncation
#let trunc(A) = [$bar.double$#A$bar.double$]
#typeIntroTable(
[If $A$ is a type, then $trunc(A)$ is a type],
[If $a:A$, then $overline(a):trunc(A)$ and $ p(A) : product_(x, y: trunc(A)) x pathto y $],
[If $f:A->B$ and $B$ is a prop, then we have $overline(f) : trunc(A) -> B$],
[$overline(f)(overline(a)) defeq f(a)$],
)
- $p(A)$ turns $trunc(A)$ into a proposition
- $trunc(A)$ is empty if $A$ is, and contractible if $A$ has one element.