{-# OPTIONS --cubical --guardedness #-}
module Padova2025.Cubical.FirstSteps where
First steps#
open import Cubical.Foundations.Prelude
open import Padova2025.ProgrammingBasics.Naturals.Base
open import Padova2025.ProgrammingBasics.Naturals.Arithmetic
open import Padova2025.ProvingBasics.Negation
open import Padova2025.ProvingBasics.Termination.Gas using (𝟙; tt)
Proper introduction. Split off menagerie of types.
Unordered pairs#
data UnorderedPair (A : Set) : Set where
pair : (x y : A) → UnorderedPair A
swap : (x y : A) → pair x y ≡ pair y x
Generalities on equality#
refl' : {X : Set} {a : X} → a ≡ a
refl' {a = a} = λ i → a
symm' : {X : Set} {a b : X} → a ≡ b → b ≡ a
symm' p = λ i → p (~ i)
cong'cong' : {X Y : Set} {a b : X} → (f : X → Y) → a ≡ b → f a ≡ f b
cong' f p = {!!}
funextfunext : {A B : Set} {f g : A → B} → ((x : A) → f x ≡ g x) → f ≡ g
funext = {!!}
Verifying transitivity is more difficult. Let us just use the function from the cubical standard library:
trans' : {X : Set} {a b c : X} → a ≡ b → b ≡ c → a ≡ c
trans' p q = p ∙ q
Even though cubical Agda reimagines identity in a radical way, in the end the primitive equality type coincides with the inductively-defined type we have been using all along:
open import Padova2025.ProvingBasics.Equality.Base renaming (_≡_ to _≡ᵢ_)
≡ᵢ→≡≡ᵢ→≡ : {X : Set} {a b : X} → a ≡ᵢ b → a ≡ b
≡ᵢ→≡ = {!!}
≡→≡ᵢ : {X : Set} {a b : X} → a ≡ b → a ≡ᵢ b
≡→≡ᵢ = J (λ b q → _ ≡ᵢ b) _≡ᵢ_.refl
Exercise: Sum of unordered pair#
open import Padova2025.ProvingBasics.Equality.NaturalNumbers
sum-pairsum-pair : UnorderedPair ℕ → ℕ
sum-pair = {!!}
Integers#
infixl 5 _⊝_
data ℤ : Set where
_⊝_ : (a b : ℕ) → ℤ
cancel : (a b : ℕ) → a ⊝ b ≡ succ a ⊝ succ b
Define the successor and predecessor functions.
succℤsuccℤ : ℤ → ℤ
succℤ (a ⊝ b) = succ a ⊝ b
succℤ (cancel a b i) = {!!}
predℤpredℤ : ℤ → ℤ
predℤ (a ⊝ b) = a ⊝ succ b
predℤ (cancel a b i) = {!!}
Exercise: One is not zero, revisited#
Show that one is not zero.
lemma-nontriviallemma-nontrivial : one ≡ zero → ⊥
lemma-nontrivial = {!!}
With the inductive definition of _≡_ we used before, this required
an empty pattern. Now that _≡_ is no longer inductively defined,
but an in-built notion, we cannot case split on equality witnesses.
Instead, proceed as follows:
- Define a function
disambig : ℕ → Setwhich maps zero to ⊥ and everything else to some inhabited type. - Assuming that there is a path
zero ≡ succ zero, combinetransportfrom the standard library anddisambig:transport : {A B : Set} → A ≡ B → A → B
Exercise: Robustness of the unordered pair abstraction#
Show that the unordered pair abstraction is not leaky, in the sense that there cannot be a function which would extract the first component of an unordered pair.
lemma-not-leakylemma-not-leaky : (f : UnorderedPair ℕ → ℕ) → ((a b : ℕ) → f (pair a b) ≡ a) → ⊥
lemma-not-leaky = {!!}
Exercise: Reversing twice#
The solution of the following exercise is delightful. No case split is needed (nor possible):
symm-symmsymm-symm : {X : Set} {a b : X} → (p : a ≡ b) → symm' (symm' p) ≡ p
symm-symm = {!!}
Mere propositions#
In homotopy type theory, a type is called a proposition if and only if all its inhabitants are equal. Hence all there is to know about a proposition is whether it is inhabited.
isProp' : Set → Set
isProp' X = (a b : X) → a ≡ b
Show that the types ⊥ and 𝟙 are propositions in this sense.
⊥-isProp⊥-isProp : isProp' ⊥
⊥-isProp = {!!}
𝟙-isProp𝟙-isProp : isProp' 𝟙
𝟙-isProp = {!!}
Show that negations are propositions.
lemma-negations-are-propslemma-negations-are-props : (X : Set) → isProp' (X → ⊥)
lemma-negations-are-props = {!!}
Zero-dimensionality of the type of natural numbers#
In homotopy type theory, a type is called hset (or just set) iff its identity types are mere propositions, i.e. iff there is at most one path between any two elements.
isHSet : Set → Set
isHSet X = (a b : X) → isProp' (a ≡ b)
To verify that ℕ is an hset, we require an explicit description of its identity types.
For the following definition of Code, it will turn out that the types a ≡ b and Code a b
are equivalent.
Code : ℕ → ℕ → Set
Code zero zero = 𝟙
Code zero (succ y) = ⊥
Code (succ x) zero = ⊥
Code (succ x) (succ y) = Code x y
fromCodefromCode : (a b : ℕ) → Code a b → a ≡ b
fromCode = {!!}
Code-reflCode-refl : (a : ℕ) → Code a a
Code-refl = {!!}
Code-isPropCode-isProp : (a b : ℕ) → isProp' (Code a b)
Code-isProp = {!!}
toCodetoCode : (a b : ℕ) → a ≡ b → Code a b
toCode a b = J {!!} {!!}
If _≡_ was the inductively-defined equality predicate from before,
we would do a case split on p to reduce to the case toCode a a refl; this case could be solved by Code-refl a.
This kind of case split is not available for _≡_, however
we can emulate its effects by the standard library’s J function.
from-to₀ : (a : ℕ) → fromCode a a (toCode a a refl') ≡ refl'
from-to₀ zero = refl'
from-to₀ (succ a) i = cong succ (from-to₀ a i)
from-to : (a b : ℕ) → (p : a ≡ b) → fromCode a b (toCode a b p) ≡ p
from-to a b p = J (λ y q → fromCode a y (toCode a y q) ≡ q) (from-to₀ a) p
ℕ-isHSetℕ-isHSet : isHSet ℕ
ℕ-isHSet = {!!}