{-# OPTIONS --allow-unsolved-metas #-}
{-
AGDA IN PADOVA 2024
Exercise sheet 4
┌─ SHORTCUTS ───────────────────────┐ ┌─ BACKSLASH CHARACTERS ─┐
│ C-c C-l = load file │ │ \bN = ℕ │
│ C-c C-c = case split │ │ \alpha = α │
│ C-c C-SPC = check hole │ │ \to = → │
│ C-c C-, = see context │ │ \cdot = · │
│ C-c C-. = see context and goal │ │ \:: = ∷ │
│ C-c C-d = display type │ │ \== = ≡ │
│ C-c C-v = evaluate expression │ └────────────────────────┘
│ C-z = enable Vi keybindings │ Use M-x describe-char to
│ C-x C-+ = increase font size │ lookup input method for
└───────────────────────────────────┘ symbol under cursor.
You can open this file in an Agdapad session by pressing C-x C-f ("find file")
and then entering the path to this file: ~/Padova2024/exercise04.agda.
As this file is read-only, you can then save a copy of this file to your personal
directory and edit that one: File > Save As... For instance, you can save this file
as ~/solutions04.agda.
-}
-- ─────────────────────────────
-- ────[ BASIC DEFINITIONS ]────
-- ─────────────────────────────
data Bool : Set where
false : Bool
true : Bool
data ℕ : Set where
zero : ℕ
succ : ℕ → ℕ
data ⊥ : Set where
infixr 5 _∷_
data List (A : Set) : Set where
[] : List A
_∷_ : A → List A → List A
infix 3 ¬_
¬_ : Set → Set
¬ X = X → ⊥
infixr 1 _⊎_
data _⊎_ (A B : Set) : Set where
left : A → A ⊎ B
right : B → A ⊎ B
infix 5 _≡_
data _≡_ {X : Set} : X → X → Set where
refl : {a : X} → a ≡ a
cong : {A B : Set} {x y : A} → (f : A → B) → x ≡ y → f x ≡ f y
cong f refl = refl
symm : {A : Set} {x y : A} → x ≡ y → y ≡ x
symm refl = refl
trans : {A : Set} {x y z : A} → x ≡ y → y ≡ z → x ≡ z
trans refl q = q
_+_ : ℕ → ℕ → ℕ
zero + b = b
succ a + b = succ (a + b)
_·_ : ℕ → ℕ → ℕ
zero · b = zero
succ a · b = b + (a · b)
-- ─────────────────────────────────────
-- ────[ CORRECTNESS OF ALGORITHMS ]────
-- ─────────────────────────────────────
module _ where private
eq? : ℕ → ℕ → Bool
eq? zero zero = true
eq? zero (succ _) = false
eq? (succ _) zero = false
eq? (succ x) (succ y) = eq? x y
-- EXERCISE. Verify that "eq?" works as intended by filling in the next two holes.
lemma-correct₁ : (x y : ℕ) → eq? x y ≡ true → x ≡ y
lemma-correct₁ = {!!}
lemma-correct₂ : (x y : ℕ) → x ≡ y → eq? x y ≡ true
lemma-correct₂ = {!!}
-- EXERCISE. Now follow the approach "correct by construction", by disregarding
-- the implementation "eq?" and its correctness lemmas and instead filling in the
-- next hole.
dec : (x y : ℕ) → (x ≡ y) ⊎ ¬ (x ≡ y)
dec x y = {!!}
module _ where private
data _≤_ : ℕ → ℕ → Set where
base : {y : ℕ} → zero ≤ y
step : {x y : ℕ} → x ≤ y → succ x ≤ succ y
-- EXERCISE. Implement the function "cmp?" which should return "true"
-- if the first argument is smaller than or equal to the second argument,
-- and "false" else. For instance "cmp? zero (succ zero)" should be "true".
cmp? : ℕ → ℕ → Bool
cmp? x y = {!!}
-- EXERCISE. Verify the correctness of "cmp?" as follows.
lemma-correct₁ : (x y : ℕ) → cmp? x y ≡ true → x ≤ y
lemma-correct₁ = {!!}
lemma-correct₂ : (x y : ℕ) → x ≤ y → cmp? x y ≡ true
lemma-correct₂ = {!!}
-- EXERCISE. Now with "correct by construction".
dec : (x y : ℕ) → (x ≤ y) ⊎ (y ≤ x)
dec = {!!}
-- ────────────────────────
-- ────[ DECIDABILITY ]────
-- ────────────────────────
-- A proposition is decidable iff it holds or if its converse holds.
data Dec (A : Set) : Set where
yes : A → Dec A
no : ¬ A → Dec A
-- EXERCISE. For every pair of numbers x, y, verify that "x ≡ y" is decidable.
dec-eq : (x y : ℕ) → Dec (x ≡ y)
dec-eq x y = {!!}
-- EXERCISE. Prove that, if "X" and "Y" are decidable, so is "X → Y".
dec-→ : {X Y : Set} → Dec X → Dec Y → Dec (X → Y)
dec-→ = {!!}
-- ──────────────────────────
-- ────[ INSERTION SORT ]────
-- ──────────────────────────
-- EXERCISE: Implement insertion sort, by filling in the two holes below.
module Implementation
{A : Set}
(_≤_ : A → A → Set)
(cmp? : (x y : A) → (x ≤ y) ⊎ (y ≤ x)) where
-- Given an ordered list "ys", "insert x ys" should be the same as "ys",
-- but with "x" inserted at the correct place to ensure that the
-- resulting list is again ordered.
insert : (x : A) → List A → List A
insert = {!!}
sort : List A → List A
sort = {!!}
module Verification₂ {A : Set} (_≤_ : A → A → Set) (cmp : (x y : A) → (x ≤ y) ⊎ (y ≤ x)) where
open Implementation _≤_ cmp
-- "(x ◂ ys ↝ xys)" should be the type of witnesses that inserting "x" into "ys" somewhere
-- yields the list "xys". -- ◂\t ↝\leadsto
data _◂_↝_ : A → List A → List A → Set where
here : {x : A} {xs : List A} → x ◂ xs ↝ (x ∷ xs)
there : {x y : A} {ys xys : List A} → x ◂ ys ↝ xys → x ◂ (y ∷ ys) ↝ (y ∷ xys)
-- "IsPerm xs ys" should be the type of witnesses that the two lists "xs" and "ys"
-- are permutations of each other, that is, contain exactly the same elements just
-- perhaps in different order.
data IsPerm : List A → List A → Set where
empty : IsPerm [] []
cons : {x : A} {xs ys xys : List A} → (x ◂ ys ↝ xys) → IsPerm xs ys → IsPerm (x ∷ xs) xys
-- EXERCISE: Make sense of the preceding two definitions.
-- EXERCISE: Fill in this hole.
example : (x y z : A) → IsPerm (x ∷ y ∷ z ∷ []) (z ∷ x ∷ y ∷ [])
example x y z = {!!}
-- EXERCISE: Verify this lemma.
lemma : (x : A) (ys : List A) → x ◂ ys ↝ insert x ys
lemma x ys = {!!}
-- EXERCISE: Deduce this theorem.
theorem : (xs : List A) → IsPerm xs (sort xs)
theorem xs = {!!}
-- A variant of what we did in the lecture.
module CorrectByConstruction₀
{A : Set} (_≤_ : A → A → Set)
(max : A) (≤max : {x : A} → x ≤ max)
(cmp : (x y : A) → (x ≤ y) ⊎ (y ≤ x)) where
-- "OList l" is the type of ordered lists of elements of A.
data OList : Set
-- The usual "where" is missing because the definition of "OList"
-- mutually depends on the following function extracting the head
-- of an ordered list.
head : OList → A
-- This is just a declaration. The definition will follow once
-- the constructors of "OList" have been introduced.
data OList where
nil : OList
cons : (x : A) (xs : OList) → x ≤ head xs → OList
head nil = max
head (cons x xs _) = x
insert : A → OList → OList
insert x ys = {!!}
sort : List A → OList
sort [] = nil
sort (x ∷ xs) = insert x (sort xs)
module CorrectByConstruction₂
{A : Set} (_≤_ : A → A → Set)
(min : A) (min≤ : {x : A} → min ≤ x)
(cmp : (x y : A) → (x ≤ y) ⊎ (y ≤ x)) where
-- As in module Verification₂ above
data _◂_↝_ : A → List A → List A → Set where
here : {x : A} {xs : List A} → x ◂ xs ↝ (x ∷ xs)
there : {x y : A} {ys xys : List A} → x ◂ ys ↝ xys → x ◂ (y ∷ ys) ↝ (y ∷ xys)
-- "OPList l xs" is the type of ordered lists whose elements are bounded from below by l
-- and which are permutations of xs
data OPList (l : A) : List A → Set where
nil : OPList l []
cons : {ys xys : List A} → (x : A) → OPList x ys → l ≤ x → (x ◂ ys ↝ xys) → OPList l xys
-- EXERCISE: Fill this in.
insert : {!!}
insert = {!!}
-- EXERCISE: Fill this in.
sort : (xs : List A) → OPList min xs
sort = {!!}
-- The modules CorrectByConstruction₁ and CorrectByConstruction₂ require a least element "min".
-- EXERCISE: Define for any type A together with a relation _≤_ on A a new
-- type "* A" which is A adjoined by a new least element -∞. Use
-- this construction to get rid of the additional requirement.
data *_ (A : Set) : Set where
-- EXERCISE: fill this in
module Lift {A : Set} (_≤_ : A → A → Set) where
-- EXERCISE: Define a relation _≼_ on * A.
-- EXERCISE: Verify that there is a least element for this relation.
-- EXERCISE: Verify that if we have a function cmp for A then we also have such a function for * A.
-- EXERCISE: Define a correct-by-construction sort function for A, by using * A.