{-# OPTIONS --allow-unsolved-metas #-}
data ℕ : Set where
zero : ℕ
succ : ℕ → ℕ
infixl 6 _+_
_+_ : ℕ → ℕ → ℕ
_+_ = {!!}
infixl 5 _≡_
data _≡_ {X : Set} : X → X → Set where
refl : {x : X} → x ≡ x
module Experiment where
pred : ℕ → ℕ
pred zero = zero
pred (succ n) = n
pred' : ℕ → ℕ
pred' = pred
_ : pred ≡ pred'
_ = refl
pred'' : ℕ → ℕ
pred'' zero = zero
pred'' (succ n) = n
-- NOTE: Without using the funext postulate from below, there is no
-- way of filling in this hole!
_ : pred ≡ pred''
_ = {!!}
lemma : (n : ℕ) → pred n ≡ pred'' n
lemma zero = refl
lemma (succ n) = refl
-- Ordinary blackboard mathematics employs the following axiom:
-- FUNCTION EXTENSIONALITY: Functions which are pointwise equal
-- (i.e. functions which produce the same output on each input) are
-- equal.
postulate
funext : {A B : Set} {f g : A → B} → ((x : A) → f x ≡ g x) → f ≡ g
-- ^^^^^^^^^^^^^^^^^^^^^ ^^^^^
-- f and g are pw. equal f and g are equal
theorem : pred ≡ pred''
theorem = funext lemma
-- In case you need function extensionality, you can just postulate it.
-- However note that this will destroy canonicity:
-- Canonicity is the property that every term of type ℕ reduces to a numeral
-- (to a term of the form succ (succ (succ ... (zero)...))).
-- More generally, canonicity is the property that every term of
-- every inductively generated type reduces to a term which begins with
-- one of the constructors.
-- Without custom postulates, Agda does have the canonicity property.
-- Hence any term of type x ≡ y reduces to refl. Not so "theorem" above.
module Fail where
data ℤ : Set where
inj : ℕ → ℤ -- "inject", "injection"
neg : ℕ → ℤ
-- Values of ℤ:
-- inj zero (0), inj (succ zero) (1), inj (succ (succ zero)) (2), ...
-- neg zero (-1), neg (succ zero) (-2), neg (succ (succ zero)) (-3), ...
add : ℤ → ℤ → ℤ
add (inj x) (inj y) = inj (x + y)
add (inj x) (neg y) = {!!}
add (neg x) (inj y) = {!!}
add (neg x) (neg y) = neg (succ (x + y))
-- Informally:
-- add (neg x) (neg y) = neg x + neg y = -1-x + -1-y = -1-(x+y+1)
-- This approach is neither suited for definitions nor for verifying properties!
module Pre-Integers where
open import Data.Product
-- the type of "pre-integers" (representations of integers)
Z = ℕ × ℕ
-- for instance, (succ (succ zero) , succ zero) : Z; this denotes 2-1 (so 1).
-- for instance, (succ zero , succ (succ (succ zero))) : Z; this denotes 1-3 (so -2).
-- Note: (zero , zero) and (succ zero , succ zero) and (n , n) all denote the same integer 0.
add : Z → Z → Z
add (a , b) (a' , b') = a + a' , b + b'
-- Informally: (a-b) + (a'-b') = (a+a') - (b+b')
-- "x ≈ y" should be the type of witnesses that the two pre-integers "x" and "y"
-- denote the same integer.
_≈_ : Z → Z → Set
-- (a , b) ≈ (a' , b') = {!a-b ≡ a'-b'!}
(a , b) ≈ (a' , b') = b' + a ≡ a' + b
_ : (zero , zero) ≈ (succ (succ zero) , succ (succ zero))
_ = refl
-- The true type of integers would be the quotient of Z by the equivalence relation _≈_.
-- So the values of the true type ℤ of integers would be equivalence classes [ x ]
-- such that [ x ] ≡ [ y ] iff x ≈ y.
-- ISSUE: In Agda, we don't have quotients.
-- There is no keyword "quotient" like: ℤ = quotient Z _≈_
-- The next module will postulate those!
-- Module to postulate quotients, as Agda doesn't have them
module Quotient (A : Set) (_~_ : A → A → Set) (isEquivalence : {!!}) where
postulate
Q : Set
[_] : A → Q -- intuitively, [ x ] should be the equivalence class of x
eq : {x y : A} → x ~ y → [ x ] ≡ [ y ]
exact : {x y : A} → [ x ] ≡ [ y ] → x ~ y
rec : {B : Set} (f : A → B) → ((x y : A) → x ~ y → f x ≡ f y) → (Q → B)
comp : {B : Set} (f : A → B) → (ext : (x y : A) → x ~ y → f x ≡ f y) {x : A} → rec f ext ([ x ]) ≡ f x
-- This is the recursor and its computation rule.
-- We also need the induction principle and the computation rule for that (both not shown here).
-- In fact, the induction principle and its computation rule render the recursor and its rule superfluous.
module Integers where
open import Data.Product
open Quotient Pre-Integers.Z Pre-Integers._≈_ {!!}
ℤ : Set
ℤ = Q
integer-zero : ℤ
integer-zero = [ (zero , zero) ]
integer-minusone : ℤ
integer-minusone = [ (zero , succ zero) ]
module RecordExample where
String : Set
String = ℕ
record Person : Set where
field
name : String
address : String
age : ℕ
ex : Person
ex = record
{ name = {!!}
; address = {!!}
; age = {!!}
}
f : Person → ℕ
f x = Person.age x + succ zero
{-
open Person
g : Person → ℕ
g x = age x + succ zero
-}
h = age + succ zero
where
open Person ex
record IsEquivalence {X : Set} (_~_ : X → X → Set) : Set where
field
reflexive : {x : X} → x ~ x
symmetric : {x y : X} → x ~ y → y ~ x
transitive : {x y z : X} → x ~ y → y ~ z → x ~ z
lemma-≈-is-equivalence-relation : IsEquivalence Pre-Integers._≈_
lemma-≈-is-equivalence-relation = record { reflexive = {!!} ; symmetric = {!!} ; transitive = {!!} }
-- Introduction to setoid hell :-)
module Setoids where
-- A setoid is a type together with an equivalence relation on it.
-- For instance, the type Z of pre-integers together with _≈_ is a setoid.
-- Functions between setoids are by definitions functions between
-- the underlying types which respect the given equivalence
-- relations.
record Setoid : Set₁ where
field
Carrier : Set
_~_ : Carrier → Carrier → Set
isEquiv : IsEquivalence _~_
ℤ' : Setoid
ℤ' = record { Carrier = Pre-Integers.Z ; _~_ = Pre-Integers._≈_ ; isEquiv = lemma-≈-is-equivalence-relation }
record _⇒_ (X Y : Setoid) : Set where
field
fun : Setoid.Carrier X → Setoid.Carrier Y
track : {x x' : Setoid.Carrier X} → Setoid._~_ X x x' → Setoid._~_ Y (fun x) (fun x')
open import Data.Product
negation : ℤ' ⇒ ℤ'
negation = record
{ fun = λ { (a , b) → (b , a) }
; track = {!!}
}