-- Playing with Agda in your browser: agdapad.quasicoherent.io
-- Course on Agda: lets-play-agda.quasicoherent.io
{-# OPTIONS --cubical #-}
open import Cubical.Core.Everything
open import Cubical.Foundations.Prelude
{-
Possible projects for this tutorial
(can also be mixed to some extent):
1. commutativity of addition
2. correctness of insertion sort
3. set theory (via sets as trees)
4. something else?
-}
-- zero : ℕ : Set : Set₁ : Set₂ : ... : Setω : Setω1 : ...
-- Level
-- Set = the type of all small types
-- Set₁ = the type of all large types
-- Set₂ = the type of all very large types
data ℕ : Set where -- \bN \alpha \to
zero : ℕ
succ : ℕ → ℕ
-- Inhabitants of ℕ are:
-- zero, succ zero, succ (succ zero), succ (succ (succ zero)), ...
-- Ctrl-c Ctrl-l: load file
-- in blackboard mathematics: f(x)
-- in Agda: f x
one : ℕ
one = succ zero
two : ℕ
two = succ one
twice : ℕ → ℕ
twice zero = zero
twice (succ x) = succ (succ (twice x))
-- Ctrl-c Ctrl-c: case split
-- Ctrl-c Ctrl-SPACE: ask Agda to accept our input in the hole
{-# BUILTIN NATURAL ℕ #-}
-- In Agda, the activities of proving and programming are unified.
-- For each assertion, we write up in Agda the type of its witnesses.
-- To prove an assertion, we write down an inhabitant of the type of witnesses.
-- For any two natural numbers x and y, there is the type (x ≡ y).
-- This type contains witnesses that x equals y.
-- For instance, the type (zero ≡ one) is empty.
-- For instance, the type (zero ≡ zero) is inhabited.
grande-teorema : (zero ≡ zero)
grande-teorema = refl
grande-teorema' : (twice 42 ≡ 84)
grande-teorema' = refl
_+_ : ℕ → (ℕ → ℕ)
zero + y = y
succ x + y = succ (x + y)
-- Computational reading: "lemma" is a function which inputs a number y : ℕ
-- and which outputs a witness that zero + y equals y.
-- Logical reading: For every number y : ℕ, zero + y equals y.
lemma : (y : ℕ) → (zero + y ≡ y) -- \==
lemma y = refl
-- Ctrl-c Ctrl-COMMA: display the current situation
-- Ctrl-c Ctrl-a: automatic mode
-- In Cubical Agda, there is an inbuilt type I representing the unit interval.
-- i0 : I
-- i1 : I
-- (i½ : I)
refl' : {X : Set} → {a : X} → (a ≡ a)
refl' {X} {a} = λ i → a
-- Ctrl-c Ctrl-r: automatic mode, but just for one step
-- on a blackboard: (i ↦ ...)
-- in lambda calculus: λi. ...
symm' : {X : Set} → {a b : X} → a ≡ b → b ≡ a
symm' p = λ i → p (~ i)
-- Here p is a path from a to b, so a function I → X such that p i0 is a and p i1 is b.
-- We need to construct a path q from b to a.
-- On a blackboard: q(i) := p(1-i)
-- On a blackboard: q := (i ↦ p(1-i))
-- Logical reading: For every type X, for every type X, for every elements a, b : X,
-- for every function f : X → Y, if a equals b, then f(a) equals f(b).
-- Computational reading "cong'" is a function which inputs
-- 1. a type X (implicitly)
-- 2. a type Y (implicitly)
-- 3. an element a : X (implicitly)
-- 4. an element b : X (implicitly)
-- 5. a function f : X → Y
-- 6. a witness that a equals b
-- and outputs a witness that f(a) equals f(b).
cong' : {X Y : Set} → {a b : X} → (f : X → Y) → a ≡ b → f a ≡ f b
-- cong' f p = λ i → f (p i)
cong' f p i = f (p i)
lemma' : (x : ℕ) → (x + zero ≡ x)
lemma' zero = refl
lemma' (succ x) = cong' succ (lemma' x)
data OrderedPair : Set where
mk : ℕ → ℕ → OrderedPair
data UnorderedPair : Set where
mk : ℕ → ℕ → UnorderedPair
swap : (a b : ℕ) → mk a b ≡ mk b a
data S¹ : Set where
base : S¹
loop : base ≡ base