{-# OPTIONS --cubical --allow-unsolved-metas #-}
module AFF2024.AgdaTutorial.Session1 where
data ℕ : Set where -- \bN \to
zero : ℕ
succ : ℕ → ℕ
-- The inhabitants of ℕ are:
-- zero, succ zero, succ (succ zero), ...
-- in blackboard maths: f(x)
-- in Agda: f x
one : ℕ
one = succ zero
-- For instance, pred 5 should be 4.
pred : ℕ → ℕ
pred zero = zero
pred (succ n) = n
id : ℕ → ℕ
id zero = zero
id (succ n) = succ n
-- For instance, double 5 should be 10.
double : ℕ → ℕ
double zero = zero
double (succ n) = succ (succ (double n)) -- 2*(1+n) = 2+2n = 2+double(n)
data Bool : Set where
false : Bool
true : Bool
!_ : (b : Bool) → Bool
! false = true
! true = false
_+_ : ℕ → ℕ → ℕ
zero + b = b
succ a + b = succ (a + b) -- a + succ b, succ (b + a)
addthree : ℕ → ℕ
addthree = _+_ (succ (succ (succ zero)))
-- For instance, 3 ! should be 3 * 2 * 1 = 6.
_! : ℕ → ℕ
n ! = {!!}
-- In Agda, for every x and for every y,
-- there is a type called "x ≡ y".
-- The inhabitants of this type are witnesses that x and y are equal.
-- For instance, the type "zero ≡ one" is empty.
-- In constrast, the type "zero ≡ zero" is inhabited.
-- This way the activities of proving and programming are unified!
-- For every x : ℕ and for every y : ℕ, the following declaration sets up
-- a type called "x ≡ y" (could be also written as "_≡_ x y")
data _≡_ : ℕ → ℕ → Set where
-- Logical reading: For every x : ℕ, x equals x.
-- Computational reading: "refl" is a function which inputs a number "x"
-- and outputs a witness that x equals x.
refl : {x : ℕ} → x ≡ x
--bailout : zero ≡ one
--extreme : {x : ℕ} → x ≡ succ x
---- would still NOT have: succ x ≡ x
lemma : zero ≡ zero -- \==
lemma = refl
-- Logical reading: For every b : ℕ, zero + b equals b.
-- Computational reading: "insight" is a function which reads a number "b" as input
-- and outputs a witness that zero + b equals b.
insight : (b : ℕ) → (zero + b) ≡ b
insight b = refl
impossible : (b : ℕ) → (zero + b) ≡ succ b
impossible b = {!!}
-- Logical reading: For every f : ℕ → ℕ, for every a : ℕ, for every b : ℕ, if a equals b, then
-- succ a equals succ b.
-- Computational reading: "cong" is a function which inputs
-- (0) a function f : ℕ → ℕ
-- (1) a number a : ℕ
-- (2) a number b : ℕ
-- (3) a witness that a equals b
-- and outputs a witness that succ a equals succ b.
-- cong : (f : ℕ → ℕ) → {a : ℕ} → {b : ℕ} → a ≡ b → f a ≡ f b
cong : (f : ℕ → ℕ) {a b : ℕ} → a ≡ b → f a ≡ f b
cong f refl = refl
-- proof of an universal statement (∀x...) on a blackboard =
-- function which works for arbitrary inputs in Agda
-- Logical reading: For every a : ℕ, a + zero equals a.
-- Computational reading: "insight'" is a function which inputs a number a : ℕ
-- and outputs a witness that a + zero equals a.
insight' : (a : ℕ) → (a + zero) ≡ a
insight' zero = refl
insight' (succ x) = cong succ (insight' x)
addtwo : ℕ → ℕ
-- addtwo n = succ (succ n)
addtwo = λ n → succ (succ n)
-- in Python: addtwo = lambda n: succ(succ(n))
-- the empty type
data ⊥ : Set where
-- in Agda and generally in logic: ⊥ ("bottom")
-- on a blackboard: ↯
¬_ : Set → Set
¬ A = (A → ⊥)
-- In formal logic, the definition of ¬A is that A implies a contradiction.
postulate
bar : (x : ℕ) → addtwo x ≡ x
oracle : (A : Set) → ¬ ¬ A → A
-- ∃ X P is the type of witnesses that there is an x : X such that P x.
-- More precisely, an inhabitant of ∃ X P is a pair (x , p)
-- consisting of an x : X and a witness p : P x.
data ∃ (X : Set) (P : X → Set) : Set where
_,_ : (x : X) → P x → ∃ X P
-- Logical reading: There is a natural number n : ℕ such that succ n equals one.
theorem : ∃ ℕ (λ n → succ n ≡ one) -- ∃[ n ∈ ℕ ] succ n ≡ one
theorem = zero , refl
-- proof by induction on a blackboard = definition by recursion in Agda
-- typical de Bruijn factor: formalized proofs are ten times longer
-- than blackboard proofs
{-
Teaser: In Cubical Agda, we can define spaces (homotopy types)
succinctly as follows:
data Circle : Set where
north : Circle
loop : north ≡ north
data Segment : Set where
left : Segment
right : Segment
path : left ≡ right
-}