Huh, no matter how much I think I basically understand HoTT, there's always more interesting subtleties in how it interacts with my expectations of how doing math usually works. Here's an example where a naive understanding of what it means to have unique typing derivations fails.
Suppose it were true that for any notion of term and type, where every term is well-typed and synthesizes its type (via
GetTy) that every two derivations of the trivial typing relation are the same.
{-# OPTIONS --without-K --rewriting #-}
module Example where
open import HoTT
module UniqueOf (Tm : Set) (Ty : Set) (GetTy : Tm → Ty) where
data Of (M : Tm) : Ty → Set where
OfTm : Of M (GetTy M)
postulate
OfSame : (M : Tm) (A : Ty) (of1 of2 : Of M A) → of1 == of2
This seems innocuous, right? There's only one way to prove
Of for a given term (namely
OfTm) so any two such proofs ought to be the same.
Nope! From this we can prove uniqueness of identity types across all types, not a contradiction, but definitely anathema to the idea that types are potentially spaces with rich path structure:
EqSame : (A : Set) (a b : A) (p q : a == b) → p == q
EqSame A a b p q = ! (cvtinv p) ∙ ap cvti cvtEq ∙ cvtinv q where
open UniqueOf A A (λ x → x)
cvt : {a b : A} → (a == b) → Of a b
cvt idp = OfTm
cvti : {a b : A} → Of a b → (a == b)
cvti OfTm = idp
cvtinv : {a b : A} (x : a == b) → cvti (cvt x) == x
cvtinv idp = idp
cvtEq : cvt p == cvt q
cvtEq = OfSame a b (cvt p) (cvt q)
(this is really just the one-endpoint vs. two-endpoint path type distinction in disguise; what I find interesting about it is that it's so shallowly disguised, but still caught me off-guard)