πŸ“œ ⬆️ ⬇️

Verified QuickSort on Agda

Good day, dear habrauzer!

Having read several books on typed lambda calculus, namely on dependent types, I saw an interesting pattern: everywhere the first example is the definition of the β€œsorted list” type. Everything would be fine, but there was nothing beyond this definition. So I thought up to fill this gap and implement a function that accepts the list, and returns another list and two proofs. One proves that the result is a permutation of the input, and the other proves that the result is a sorted list.


Formal description


')
In this section, I will provide the basic types that will be used further, and some auxiliary functions. Also here will be shown some interesting syntactic charms of Agda. For those who are not very familiar with Agda, I recommend watching the video / slides of Jan Malakhovsky at the SPbHUG / FProg 2012-07 meeting - in my opinion, this is the only introduction to Agda in Russian (well, I haven’t met again). Or browse through the manual from the Agda site (it is not large) or this tutorial .

List definitions

data List {a} (A : Set a) : Set a where [] : List A _∷_ : (x : A) (xs : List A) β†’ List A [_] : βˆ€ {a} {A : Set a} β†’ A β†’ List A [ x ] = x ∷ [] _++_ : βˆ€ {a} {A : Set a} β†’ List A β†’ List A β†’ List A [] ++ ys = ys (x ∷ xs) ++ ys = x ∷ (xs ++ ys) 

Here we have a list. The definition is taken from the standard library. As you can see, the elements of the list can be values ​​of any type, even types and types of types and so on. This is possible due to the use of high-order polymorphism: the parameter a is introduced, which is responsible for the level, that is, the usual types are of type Set 0 , Set 0 is of type Set 1 , etc.
Also in this definition you can see how in Agda operators are declared, namely through underscores, in which place there will be arguments. It should be noted that this method allows you to define very different and very interesting forms, such as a function that returns a list from a single element [_] .

It should be noted that for all operators (combinators with underscores) you can specify the priority and associativity. Also in Agda, any Unicode sequence without spaces and brackets (round and curly) is a term.
You should also pay attention to the parentheses and curly braces: curly brackets in the type indication say that this argument is implicit and will be output by the compiler.

Type "sorted list"

 data Sorted {A} (_≀_ : A β†’ A β†’ Set) : List A β†’ Set where nil : Sorted _≀_ [] one : {x : A} β†’ Sorted _≀_ [ x ] two : {x : A} β†’ βˆ€ {yl} β†’ x ≀ y β†’ Sorted _≀_ (y ∷ l) β†’ Sorted _≀_ (x ∷ y ∷ l) 

This definition of the predicate is "sorted list". Designers should be considered as axioms. We have axioms nil and one which say that the empty list and the list with one element are sorted. We also see that the Sorted type depends on the predicate _≀_ , which is responsible for the order β€” something like the comparison function, but dependently type (the arguments are values ​​of the usual type, and the result is some type whose value is proof). Axiom two says the following: if we have evidence that x ≀ y ( x ≀ y is a type, and a value of type x ≀ y is proof that x ≀ y . See the Curry-Howard isomorphism ), and proof that some list with head y is sorted (this proof is a value of type Sorted _≀_ (y l)) , then the list x ∷ y ∷ l will also be sorted.

Type "permutation"

 data Permutation {A} : List A β†’ List A β†’ Set where refl : βˆ€ {l} β†’ Permutation ll perm : βˆ€ {l} l₁ x₁ xβ‚‚ lβ‚‚ β†’ Permutation l (l₁ ++ xβ‚‚ ∷ x₁ ∷ lβ‚‚) β†’ Permutation l (l₁ ++ x₁ ∷ xβ‚‚ ∷ lβ‚‚) 

Type (predicate) "permutation". Arguments are two lists. Input axioms: refl - the list is a permutation of itself; perm - if we have a proof that some list l is a permutation of another list l₁ ++ xβ‚‚ ∷ x₁ ∷ lβ‚‚ (proof of this is a value of type Permutation l (l₁ ++ xβ‚‚ ∷ x₁ ∷ lβ‚‚) ), then if you rearrange two arbitrary element in places, we get that the new list is a permutation of the first one.

Type "amount"

 data _⊎_ {ab} (A : Set a) (B : Set b) : Set (a βŠ” b) where inj₁ : (x : A) β†’ A ⊎ B injβ‚‚ : (y : B) β†’ A ⊎ B 

Well, everything is simple - it is not dependent type - analog of Either in Haskell.

Type Product

 record Ξ£ {ab} (A : Set a) (B : A β†’ Set b) : Set (a βŠ” b) where constructor _,_ field proj₁ : A projβ‚‚ : B proj₁ syntax Ξ£ A (Ξ» x β†’ B) = Ξ£[ x ∢ A ] B _Γ—_ : βˆ€ {ab} (A : Set a) (B : Set b) β†’ Set (a βŠ” b) A Γ— B = Ξ£[ _ ∢ A ] B 

This is an analogue of a tuple. The record is used, since this type can have only one constructor. This definition uses the dependent type: the first element is a value, and the second is the proof of the execution of a predicate on this element. But, of course, you don’t have to use it this way, you can just like a regular tuple (through _ Γ— _ ) - then the dependence between the elements is ignored. syntax allows new syntaxes to be defined if there are few simple possibilities.

Sort function

 sort : {A : Set} {_≀_ : A β†’ A β†’ Set} β†’ (βˆ€ xy β†’ (x ≀ y) ⊎ (y ≀ x)) β†’ (l : List A) β†’ Ξ£[ l' ∢ List A ] (Sorted _≀_ l' Γ— Permutation l l') 

Finally, we describe the type of the sort function: this function accepts (implicitly) a predicate that determines the order, also a function that for input values ​​returns a proof that the first is greater than the second or that the second is greater than the first. I think the reader guessed that this function will be used to build evidence of the sorting of the result list. Also, of course, one of the input parameters is a list that will be sorted.
The sort function returns a list and two proofs (sorting and permutations).

Implement the sort function


Of course, no implementation of this function will be here - not that I would be sorry to show the code, I feel sorry for myself to explain it. Therefore, I will give proofs (implementations) of some auxiliary functions that I needed while writing the sort function.
A working source can be found here.
Used by Agda-2.3.1 and Standard Library-0.6
 {-# OPTIONS --no-termination-check #-} module QuickSort where open import IO.Primitive using () renaming (putStrLn to putCoStrLn) open import Data.String using (toCostring; String) renaming (_++_ to _+s+_) open import Data.List open import Data.Nat open import Data.Nat.Show open import Data.Sum open import Data.Product open import Relation.Binary.Core open import Function data Sorted {A} (_≀_ : A β†’ A β†’ Set) : List A β†’ Set where nil : Sorted _≀_ [] one : {x : A} β†’ Sorted _≀_ [ x ] two : {x : A} β†’ βˆ€ {yl} β†’ x ≀ y β†’ Sorted _≀_ (y ∷ l) β†’ Sorted _≀_ (x ∷ y ∷ l) data Permutation {A} : List A β†’ List A β†’ Set where refl : βˆ€ {l} β†’ Permutation ll perm : βˆ€ {l} l₁ x₁ xβ‚‚ lβ‚‚ β†’ Permutation l (l₁ ++ xβ‚‚ ∷ x₁ ∷ lβ‚‚) β†’ Permutation l (l₁ ++ x₁ ∷ xβ‚‚ ∷ lβ‚‚) ≑-elim : βˆ€ {l} {A : Set l} {xy : A} β†’ x ≑ y β†’ (P : A β†’ Set l) β†’ P x β†’ P y ≑-elim refl _ p = p ≑-sym : βˆ€ {l} {A : Set l} {xy : A} β†’ x ≑ y β†’ y ≑ x ≑-sym refl = refl ≑-trans : βˆ€ {l} {A : Set l} {xyz : A} β†’ x ≑ y β†’ y ≑ z β†’ x ≑ z ≑-trans refl refl = refl ++-assoc : βˆ€ {l} {A : Set l} (l₁ lβ‚‚ l₃ : List A) β†’ (l₁ ++ lβ‚‚) ++ l₃ ≑ l₁ ++ (lβ‚‚ ++ l₃) ++-assoc [] lβ‚‚ l₃ = refl ++-assoc (h ∷ t) lβ‚‚ l₃ = ≑-elim (≑-sym $ ++-assoc t lβ‚‚ l₃) (Ξ» x β†’ h ∷ x ≑ h ∷ t ++ (lβ‚‚ ++ l₃)) refl decNat : (xy : β„•) β†’ (x ≀ y) ⊎ (y ≀ x) decNat zero y = inj₁ z≀n decNat (suc x) (suc y) with decNat xy ... | inj₁ p = inj₁ (s≀sp) ... | injβ‚‚ p = injβ‚‚ (s≀sp) decNat (suc x) zero = injβ‚‚ z≀n perm-trans : βˆ€ {A} {l₁ lβ‚‚ l₃ : List A} β†’ Permutation l₁ lβ‚‚ β†’ Permutation lβ‚‚ l₃ β†’ Permutation l₁ l₃ perm-trans p refl = p perm-trans p₁ (perm l₁ x₁ xβ‚‚ lβ‚‚ pβ‚‚) = perm l₁ x₁ xβ‚‚ lβ‚‚ $ perm-trans p₁ pβ‚‚ perm-sym : βˆ€ {A} {l₁ lβ‚‚ : List A} β†’ Permutation l₁ lβ‚‚ β†’ Permutation lβ‚‚ l₁ perm-sym refl = refl perm-sym (perm l₁ x₁ xβ‚‚ lβ‚‚ p) = perm-trans (perm l₁ xβ‚‚ x₁ lβ‚‚ refl) (perm-sym p) perm-del-ins-r : βˆ€ {A} (l₁ : List A) (x : A) (lβ‚‚ l₃ : List A) β†’ Permutation (l₁ ++ x ∷ lβ‚‚ ++ l₃) (l₁ ++ lβ‚‚ ++ x ∷ l₃) perm-del-ins-r l₁ x [] l₃ = refl perm-del-ins-r l₁ x (h ∷ t) l₃ = perm-trans pβ‚€ pβ‚… where pβ‚€ : Permutation (l₁ ++ x ∷ h ∷ t ++ l₃) (l₁ ++ h ∷ x ∷ t ++ l₃) pβ‚€ = perm l₁ hx (t ++ l₃) refl p₁ : Permutation ((l₁ ++ [ h ]) ++ x ∷ t ++ l₃) ((l₁ ++ [ h ]) ++ t ++ x ∷ l₃) p₁ = perm-del-ins-r (l₁ ++ [ h ]) xt l₃ pβ‚‚ : (l₁ ++ [ h ]) ++ t ++ x ∷ l₃ ≑ l₁ ++ h ∷ t ++ x ∷ l₃ pβ‚‚ = ++-assoc l₁ [ h ] (t ++ x ∷ l₃) p₃ : (l₁ ++ [ h ]) ++ x ∷ t ++ l₃ ≑ l₁ ++ h ∷ x ∷ t ++ l₃ p₃ = ++-assoc l₁ [ h ] (x ∷ t ++ l₃) pβ‚„ : Permutation ((l₁ ++ [ h ]) ++ x ∷ t ++ l₃) (l₁ ++ h ∷ t ++ x ∷ l₃) pβ‚„ = ≑-elim pβ‚‚ (Ξ» y β†’ Permutation ((l₁ ++ [ h ]) ++ x ∷ t ++ l₃) y) p₁ pβ‚… : Permutation (l₁ ++ h ∷ x ∷ t ++ l₃) (l₁ ++ h ∷ t ++ x ∷ l₃) pβ‚… = ≑-elim p₃ (Ξ» y β†’ Permutation y (l₁ ++ h ∷ t ++ x ∷ l₃)) pβ‚„ perm-del-ins-l : βˆ€ {A} (l₁ lβ‚‚ : List A) (x : A) (l₃ : List A) β†’ Permutation (l₁ ++ lβ‚‚ ++ x ∷ l₃) (l₁ ++ x ∷ lβ‚‚ ++ l₃) perm-del-ins-l l₁ lβ‚‚ x l₃ = perm-sym $ perm-del-ins-r l₁ x lβ‚‚ l₃ perm-++ : βˆ€ {A} {x₁ y₁ xβ‚‚ yβ‚‚ : List A} β†’ Permutation x₁ y₁ β†’ Permutation xβ‚‚ yβ‚‚ β†’ Permutation (x₁ ++ xβ‚‚) (y₁ ++ yβ‚‚) perm-++ refl refl = refl perm-++ (perm {x₁} l₁ e₁ eβ‚‚ lβ‚‚ p) (refl {zβ‚‚}) = perm-trans pβ‚… p₇ where p₁ : Permutation (x₁ ++ zβ‚‚) ((l₁ ++ eβ‚‚ ∷ e₁ ∷ lβ‚‚) ++ zβ‚‚) p₁ = perm-++ p refl pβ‚‚ : (l₁ ++ eβ‚‚ ∷ e₁ ∷ lβ‚‚) ++ zβ‚‚ ≑ l₁ ++ (eβ‚‚ ∷ e₁ ∷ lβ‚‚) ++ zβ‚‚ pβ‚‚ = ++-assoc l₁ (eβ‚‚ ∷ e₁ ∷ lβ‚‚) zβ‚‚ p₃ : l₁ ++ (eβ‚‚ ∷ e₁ ∷ lβ‚‚) ++ zβ‚‚ ≑ l₁ ++ eβ‚‚ ∷ (e₁ ∷ lβ‚‚) ++ zβ‚‚ p₃ = ≑-elim (++-assoc [ eβ‚‚ ] (e₁ ∷ lβ‚‚) zβ‚‚) (Ξ» x β†’ l₁ ++ (eβ‚‚ ∷ e₁ ∷ lβ‚‚) ++ zβ‚‚ ≑ l₁ ++ x) refl pβ‚„ : l₁ ++ eβ‚‚ ∷ (e₁ ∷ lβ‚‚) ++ zβ‚‚ ≑ l₁ ++ eβ‚‚ ∷ e₁ ∷ lβ‚‚ ++ zβ‚‚ pβ‚„ = ≑-elim (++-assoc [ e₁ ] lβ‚‚ zβ‚‚) (Ξ» x β†’ l₁ ++ eβ‚‚ ∷ (e₁ ∷ lβ‚‚) ++ zβ‚‚ ≑ l₁ ++ eβ‚‚ ∷ x) refl gβ‚‚ : (l₁ ++ e₁ ∷ eβ‚‚ ∷ lβ‚‚) ++ zβ‚‚ ≑ l₁ ++ (e₁ ∷ eβ‚‚ ∷ lβ‚‚) ++ zβ‚‚ gβ‚‚ = ++-assoc l₁ (e₁ ∷ eβ‚‚ ∷ lβ‚‚) zβ‚‚ g₃ : l₁ ++ (e₁ ∷ eβ‚‚ ∷ lβ‚‚) ++ zβ‚‚ ≑ l₁ ++ e₁ ∷ (eβ‚‚ ∷ lβ‚‚) ++ zβ‚‚ g₃ = ≑-elim (++-assoc [ e₁ ] (eβ‚‚ ∷ lβ‚‚) zβ‚‚) (Ξ» x β†’ l₁ ++ (e₁ ∷ eβ‚‚ ∷ lβ‚‚) ++ zβ‚‚ ≑ l₁ ++ x) refl gβ‚„ : l₁ ++ e₁ ∷ (eβ‚‚ ∷ lβ‚‚) ++ zβ‚‚ ≑ l₁ ++ e₁ ∷ eβ‚‚ ∷ lβ‚‚ ++ zβ‚‚ gβ‚„ = ≑-elim (++-assoc [ eβ‚‚ ] lβ‚‚ zβ‚‚) (Ξ» x β†’ l₁ ++ e₁ ∷ (eβ‚‚ ∷ lβ‚‚) ++ zβ‚‚ ≑ l₁ ++ e₁ ∷ x) refl pβ‚… : Permutation (x₁ ++ zβ‚‚) (l₁ ++ eβ‚‚ ∷ e₁ ∷ lβ‚‚ ++ zβ‚‚) pβ‚… = ≑-elim (≑-trans pβ‚‚ $ ≑-trans p₃ pβ‚„) (Permutation (x₁ ++ zβ‚‚)) p₁ p₆ : Permutation (l₁ ++ eβ‚‚ ∷ e₁ ∷ lβ‚‚ ++ zβ‚‚) (l₁ ++ e₁ ∷ eβ‚‚ ∷ lβ‚‚ ++ zβ‚‚) p₆ = perm l₁ e₁ eβ‚‚ (lβ‚‚ ++ zβ‚‚) refl p₇ : Permutation (l₁ ++ eβ‚‚ ∷ e₁ ∷ lβ‚‚ ++ zβ‚‚) ((l₁ ++ e₁ ∷ eβ‚‚ ∷ lβ‚‚) ++ zβ‚‚) p₇ = ≑-elim (≑-sym $ ≑-trans gβ‚‚ $ ≑-trans g₃ gβ‚„) (Permutation (l₁ ++ eβ‚‚ ∷ e₁ ∷ lβ‚‚ ++ zβ‚‚)) p₆ perm-++ {_} {x₁} {y₁} .{_} .{_} p₁ (perm {xβ‚‚} l₁ e₁ eβ‚‚ lβ‚‚ pβ‚‚) = ≑-elim p₇ (Permutation (x₁ ++ xβ‚‚)) p₆ where p' : Permutation (x₁ ++ xβ‚‚) (y₁ ++ l₁ ++ eβ‚‚ ∷ e₁ ∷ lβ‚‚) p' = perm-++ p₁ pβ‚‚ p₃ : y₁ ++ l₁ ++ eβ‚‚ ∷ e₁ ∷ lβ‚‚ ≑ (y₁ ++ l₁) ++ eβ‚‚ ∷ e₁ ∷ lβ‚‚ p₃ = ≑-sym $ ++-assoc y₁ l₁ (eβ‚‚ ∷ e₁ ∷ lβ‚‚) pβ‚„ : Permutation (x₁ ++ xβ‚‚) ((y₁ ++ l₁) ++ eβ‚‚ ∷ e₁ ∷ lβ‚‚) pβ‚„ = ≑-elim p₃ (Permutation (x₁ ++ xβ‚‚)) p' pβ‚… : Permutation ((y₁ ++ l₁) ++ eβ‚‚ ∷ e₁ ∷ lβ‚‚) ((y₁ ++ l₁) ++ e₁ ∷ eβ‚‚ ∷ lβ‚‚) pβ‚… = perm (y₁ ++ l₁) e₁ eβ‚‚ lβ‚‚ refl p₆ : Permutation (x₁ ++ xβ‚‚) ((y₁ ++ l₁) ++ e₁ ∷ eβ‚‚ ∷ lβ‚‚) p₆ = perm-trans pβ‚„ pβ‚… p₇ : (y₁ ++ l₁) ++ e₁ ∷ eβ‚‚ ∷ lβ‚‚ ≑ y₁ ++ l₁ ++ e₁ ∷ eβ‚‚ ∷ lβ‚‚ p₇ = ++-assoc y₁ l₁ (e₁ ∷ eβ‚‚ ∷ lβ‚‚) ++-[] : βˆ€ {l} {A : Set l} (l : List A) β†’ l ++ [] ≑ l ++-[] [] = refl ++-[] (h ∷ t) = ≑-trans pβ‚€ p₁ where pβ‚€ : (h ∷ t) ++ [] ≑ h ∷ t ++ [] pβ‚€ = ++-assoc [ h ] t [] p₁ : h ∷ t ++ [] ≑ h ∷ t p₁ = ≑-elim (++-[] t) (Ξ» x β†’ h ∷ t ++ [] ≑ h ∷ x) refl data ConstrainedList {A} (P : A β†’ Set) : List A β†’ Set where [] : ConstrainedList P [] _∷_ : {x : A} {xs : List A} (p : P x) β†’ ConstrainedList P xs β†’ ConstrainedList P (x ∷ xs) infix 2 _∈_ data _∈_ {A} : A β†’ List A β†’ Set where exact : βˆ€ ht β†’ h ∈ h ∷ t cons : βˆ€ h {xl} β†’ x ∈ l β†’ x ∈ h ∷ l create-∈ : βˆ€ {A} (l₁ : List A) (x : A) (lβ‚‚ : List A) β†’ x ∈ (l₁ ++ x ∷ lβ‚‚) create-∈ [] x lβ‚‚ = exact x lβ‚‚ create-∈ (h₁ ∷ t₁) x lβ‚‚ = cons h₁ $ create-∈ t₁ x lβ‚‚ perm-∈ : βˆ€ {A l l'} {x : A} β†’ x ∈ l β†’ Permutation l' l β†’ x ∈ l' perm-∈ p refl = p perm-∈ {A} .{l₁ ++ x₁ ∷ xβ‚‚ ∷ lβ‚‚} {l'} {x} p₁ (perm l₁ x₁ xβ‚‚ lβ‚‚ pβ‚‚) = perm-∈ (loop l₁ x₁ xβ‚‚ lβ‚‚ p₁) pβ‚‚ where loop : βˆ€ l₁ x₁ xβ‚‚ lβ‚‚ β†’ x ∈ l₁ ++ x₁ ∷ xβ‚‚ ∷ lβ‚‚ β†’ x ∈ l₁ ++ xβ‚‚ ∷ x₁ ∷ lβ‚‚ loop [] .x xβ‚‚ lβ‚‚ (exact .x .(xβ‚‚ ∷ lβ‚‚)) = cons xβ‚‚ $ exact x lβ‚‚ loop [] .x₁ .x .lβ‚‚ (cons x₁ (exact .x lβ‚‚)) = exact x (x₁ ∷ lβ‚‚) loop [] .x₁ .xβ‚‚ lβ‚‚ (cons x₁ (cons xβ‚‚ p)) = cons xβ‚‚ $ cons x₁ p loop (.x ∷ t₁) x₁ xβ‚‚ lβ‚‚ (exact .x .(t₁ ++ x₁ ∷ xβ‚‚ ∷ lβ‚‚)) = exact x (t₁ ++ xβ‚‚ ∷ x₁ ∷ lβ‚‚) loop (.h₁ ∷ t₁) x₁ xβ‚‚ lβ‚‚ (cons h₁ p) = cons h₁ $ loop t₁ x₁ xβ‚‚ lβ‚‚ p constr-∈ : βˆ€ {A l} {x : A} β†’ βˆ€ {P} β†’ ConstrainedList P l β†’ x ∈ l β†’ P x constr-∈ [] () constr-∈ (p ∷ _) (exact _ _) = p constr-∈ (_ ∷ cl) (cons _ p) = constr-∈ cl p sortedHelperβ‚‚ : βˆ€ {A _≀_} {h : A} β†’ βˆ€ {l'} β†’ Sorted _≀_ l' β†’ βˆ€ {l} β†’ Permutation ll' β†’ ConstrainedList (Ξ» x β†’ x ≀ h) l β†’ βˆ€ {g'} β†’ Sorted _≀_ (h ∷ g') β†’ Sorted _≀_ (l' ++ h ∷ g') sortedHelperβ‚‚ {_} {_≀_} {h} {l'} sl' pll' cl {g'} sg' = loop [] l' refl sl' where loop : βˆ€ l₁ lβ‚‚ β†’ l₁ ++ lβ‚‚ ≑ l' β†’ Sorted _≀_ lβ‚‚ β†’ Sorted _≀_ (lβ‚‚ ++ h ∷ g') loop _ .[] _ nil = sg' loop l₁ .(x ∷ []) p (one {x}) = two (constr-∈ cl $ perm-∈ x∈l' pll') sg' where x∈l' : x ∈ l' x∈l' = ≑-elim p (Ξ» l β†’ x ∈ l) (create-∈ l₁ x []) loop l₁ .(x ∷ y ∷ l) p≑ (two {x} {y} {l} x≀y ps) = two x≀y $ loop (l₁ ++ [ x ]) (y ∷ l) p' ps where p' : (l₁ ++ [ x ]) ++ y ∷ l ≑ l' p' = ≑-trans (++-assoc l₁ [ x ] (y ∷ l)) p≑ sortedHelper₁ : βˆ€ {A _≀_} {h : A} β†’ βˆ€ {l'} β†’ Sorted _≀_ l' β†’ βˆ€ {l} β†’ Permutation ll' β†’ ConstrainedList (Ξ» x β†’ x ≀ h) l β†’ βˆ€ {g'} β†’ Sorted _≀_ g' β†’ βˆ€ {g} β†’ Permutation gg' β†’ ConstrainedList (Ξ» x β†’ h ≀ x) g β†’ Sorted _≀_ (l' ++ h ∷ g') sortedHelper₁ sl' pll' cl nil _ _ = sortedHelperβ‚‚ sl' pll' cl one sortedHelper₁ sl' pll' cl {h ∷ t} sg' pgg' cg = sortedHelperβ‚‚ sl' pll' cl $ two (constr-∈ cg $ perm-∈ (exact ht) pgg') sg' quickSort : {A : Set} {_≀_ : A β†’ A β†’ Set} β†’ (βˆ€ xy β†’ (x ≀ y) ⊎ (y ≀ x)) β†’ (l : List A) β†’ Ξ£[ l' ∢ List A ] (Sorted _≀_ l' Γ— Permutation l l') quickSort _ [] = [] , nil , refl quickSort {A} {_≀_} _≀?_ (h ∷ t) = loop t [] [] [] [] refl where loop : βˆ€ ilg β†’ ConstrainedList (Ξ» x β†’ x ≀ h) l β†’ ConstrainedList (Ξ» x β†’ h ≀ x) g β†’ Permutation t ((l ++ g) ++ i) β†’ Ξ£[ l' ∢ List A ] (Sorted _≀_ l' Γ— Permutation (h ∷ t) l') loop [] lg cl cg p = l' ++ h ∷ g' , sortedHelper₁ sl' pll' cl sg' pgg' cg , perm-trans p₃ pβ‚„ where lSort = quickSort _≀?_ l gSort = quickSort _≀?_ g l' = proj₁ lSort g' = proj₁ gSort sl' = proj₁ $ projβ‚‚ lSort sg' = proj₁ $ projβ‚‚ gSort pll' = projβ‚‚ $ projβ‚‚ lSort pgg' = projβ‚‚ $ projβ‚‚ gSort p₁ : Permutation (l ++ g) (l' ++ g') p₁ = perm-++ pll' pgg' pβ‚‚ : Permutation t (l' ++ g') pβ‚‚ = perm-trans (≑-elim (++-[] (l ++ g)) (Ξ» x β†’ Permutation tx) p) p₁ p₃ : Permutation (h ∷ t) (h ∷ l' ++ g') p₃ = perm-++ (refl {_} {[ h ]}) pβ‚‚ pβ‚„ : Permutation (h ∷ l' ++ g') (l' ++ h ∷ g') pβ‚„ = perm-del-ins-r [] hl' g' loop (h' ∷ t) lg cl cg p with h' ≀? h ... | inj₁ h'≀h = loop t (h' ∷ l) g (h'≀h ∷ cl) cg (perm-trans p p') where p' : Permutation ((l ++ g) ++ h' ∷ t) (h' ∷ (l ++ g) ++ t) p' = perm-del-ins-l [] (l ++ g) h' t ... | injβ‚‚ h≀h' = loop tl (h' ∷ g) cl (h≀h' ∷ cg) (perm-trans p p') where p₁ : l ++ g ++ h' ∷ t ≑ (l ++ g) ++ h' ∷ t p₁ = ≑-sym $ ++-assoc lg (h' ∷ t) pβ‚‚ : l ++ (h' ∷ g) ++ t ≑ (l ++ h' ∷ g) ++ t pβ‚‚ = ≑-sym $ ++-assoc l (h' ∷ g) t p₃ : (h' ∷ g) ++ t ≑ h' ∷ g ++ t p₃ = ++-assoc [ h' ] gt pβ‚„ : l ++ h' ∷ g ++ t ≑ l ++ (h' ∷ g) ++ t pβ‚„ = ≑-sym $ ≑-elim p₃ (Ξ» x β†’ l ++ x ≑ l ++ h' ∷ g ++ t) refl pβ‚… : Permutation (l ++ g ++ h' ∷ t) (l ++ h' ∷ g ++ t) pβ‚… = perm-del-ins-l lgh' t p₆ : Permutation ((l ++ g) ++ h' ∷ t) (l ++ h' ∷ g ++ t) p₆ = ≑-elim p₁ (Ξ» x β†’ Permutation x (l ++ h' ∷ g ++ t)) pβ‚… p' : Permutation ((l ++ g) ++ h' ∷ t) ((l ++ h' ∷ g) ++ t) p' = ≑-elim (≑-trans pβ‚„ pβ‚‚) (Ξ» x β†’ Permutation ((l ++ g) ++ h' ∷ t) x) p₆ showl : List β„• β†’ String showl [] = "[]" showl (h ∷ t) = show h +s+ "∷" +s+ showl t l₁ : List β„• l₁ = 19 ∷ 6 ∷ 13 ∷ 2 ∷ 8 ∷ 15 ∷ 1 ∷ 10 ∷ 11 ∷ 2 ∷ 17 ∷ 4 ∷ [ 3 ] lβ‚‚ = quickSort decNat l₁ main = putCoStrLn ∘ toCostring $ showl $ proj₁ lβ‚‚ 



Propositional Equivalence

 data _≑_ {a} {A : Set a} (x : A) : A β†’ Set a where refl : x ≑ x ≑-cong : βˆ€ {ab} {A : Set a} {B : Set b} {xy} β†’ x ≑ y β†’ (f : A β†’ B) β†’ fx ≑ fy ≑-cong refl _ = refl ≑-elim : βˆ€ {l} {A : Set l} {xy : A} β†’ x ≑ y β†’ (P : A β†’ Set l) β†’ P x β†’ P y ≑-elim refl _ p = p ≑-sym : βˆ€ {l} {A : Set l} {xy : A} β†’ x ≑ y β†’ y ≑ x ≑-sym refl = refl ≑-trans : βˆ€ {l} {A : Set l} {xyz : A} β†’ x ≑ y β†’ y ≑ z β†’ x ≑ z ≑-trans refl refl = refl 

As you can see, everything is simple: only one axiom that says that two objects are equal, if they are one and the same. Also here auxiliary functions are defined for working with proofs of equivalence. I think it's more understandable here. Let me explain only with the example of ≑-elim : the only value of the argument of the type x ≑ y can be refl , which has one implicit parameter, which in the ≑-elim refl _ p line is equal to both x and y , therefore, p has the same value type and P x and P y , and if the value of p is of type P y , then in this situation it will be the result of the function ≑-elim .

Associative concatenation operation

 ++-assoc : βˆ€ {l} {A : Set l} (l₁ lβ‚‚ l₃ : List A) β†’ (l₁ ++ lβ‚‚) ++ l₃ ≑ l₁ ++ (lβ‚‚ ++ l₃) ++-assoc [] lβ‚‚ l₃ = refl ++-assoc (h ∷ t) lβ‚‚ l₃ = ≑-cong (++-assoc t lβ‚‚ l₃) (Ξ» x β†’ h ∷ x) 

Here $ is nothing more than an application operator, like in Haskell. It is clear from the definition that this function (or, one can say, the lemma) proves for three arbitrary lists the associativity of the concatenation operation. I want to note that during the compilation terms are partially reduced using the existing definitions. In this function, the following happens:
term
 ≑-cong (++-assoc t lβ‚‚ l₃) (Ξ» x β†’ h ∷ x) 

has a type
 h ∷ (t ++ lβ‚‚) ++ l₃ ≑ h ∷ t ++ (lβ‚‚ ++ l₃) 

and we need a type
 (l₁ ++ lβ‚‚) ++ l₃ ≑ l₁ ++ (lβ‚‚ ++ l₃) 

or
 ((h ∷ t) ++ lβ‚‚) ++ l₃ ≑ (h ∷ t) ++ (lβ‚‚ ++ l₃) 

this given that
 l₁ = h ∷ t 

further, the compiler, using the definition of concatenation, reduces these terms to some general form.
Try with a term using concatenation definition,
 ((h ∷ t) ++ lβ‚‚) ++ l₃ ≑ (h ∷ t) ++ (lβ‚‚ ++ l₃) 

get a term
 h ∷ (t ++ lβ‚‚) ++ l₃ ≑ h ∷ t ++ (lβ‚‚ ++ l₃) 

It should also be borne in mind that the concatenation operation is right associative - but this is not important for understanding.

The transitivity and symmetry of the permutation

 perm-trans : βˆ€ {A} {l₁ lβ‚‚ l₃ : List A} β†’ Permutation l₁ lβ‚‚ β†’ Permutation lβ‚‚ l₃ β†’ Permutation l₁ l₃ perm-trans p refl = p perm-trans p₁ (perm l₁ x₁ xβ‚‚ lβ‚‚ pβ‚‚) = perm l₁ x₁ xβ‚‚ lβ‚‚ $ perm-trans p₁ pβ‚‚ perm-sym : βˆ€ {A} {l₁ lβ‚‚ : List A} β†’ Permutation l₁ lβ‚‚ β†’ Permutation lβ‚‚ l₁ perm-sym refl = refl perm-sym (perm l₁ x₁ xβ‚‚ lβ‚‚ p) = perm-trans (perm l₁ xβ‚‚ x₁ lβ‚‚ refl) (perm-sym p) 


"Long" rearrangement left and right

 perm-del-ins-r : βˆ€ {A} (l₁ : List A) (x : A) (lβ‚‚ l₃ : List A) β†’ Permutation (l₁ ++ x ∷ lβ‚‚ ++ l₃) (l₁ ++ lβ‚‚ ++ x ∷ l₃) perm-del-ins-r l₁ x [] l₃ = refl perm-del-ins-r l₁ x (h ∷ t) l₃ = perm-trans pβ‚€ pβ‚… where pβ‚€ : Permutation (l₁ ++ x ∷ h ∷ t ++ l₃) (l₁ ++ h ∷ x ∷ t ++ l₃) pβ‚€ = perm l₁ hx (t ++ l₃) refl p₁ : Permutation ((l₁ ++ [ h ]) ++ x ∷ t ++ l₃) ((l₁ ++ [ h ]) ++ t ++ x ∷ l₃) p₁ = perm-del-ins-r (l₁ ++ [ h ]) xt l₃ pβ‚‚ : (l₁ ++ [ h ]) ++ t ++ x ∷ l₃ ≑ l₁ ++ h ∷ t ++ x ∷ l₃ pβ‚‚ = ++-assoc l₁ [ h ] (t ++ x ∷ l₃) p₃ : (l₁ ++ [ h ]) ++ x ∷ t ++ l₃ ≑ l₁ ++ h ∷ x ∷ t ++ l₃ p₃ = ++-assoc l₁ [ h ] (x ∷ t ++ l₃) pβ‚„ : Permutation ((l₁ ++ [ h ]) ++ x ∷ t ++ l₃) (l₁ ++ h ∷ t ++ x ∷ l₃) pβ‚„ = ≑-elim pβ‚‚ (Ξ» y β†’ Permutation ((l₁ ++ [ h ]) ++ x ∷ t ++ l₃) y) p₁ pβ‚… : Permutation (l₁ ++ h ∷ x ∷ t ++ l₃) (l₁ ++ h ∷ t ++ x ∷ l₃) pβ‚… = ≑-elim p₃ (Ξ» y β†’ Permutation y (l₁ ++ h ∷ t ++ x ∷ l₃)) pβ‚„ perm-del-ins-l : βˆ€ {A} (l₁ lβ‚‚ : List A) (x : A) (l₃ : List A) β†’ Permutation (l₁ ++ lβ‚‚ ++ x ∷ l₃) (l₁ ++ x ∷ lβ‚‚ ++ l₃) perm-del-ins-l l₁ lβ‚‚ x l₃ = perm-sym $ perm-del-ins-r l₁ x lβ‚‚ l₃ 

These features are more interesting. Here I just want to note that if we consider types as theorems or lemmas, and terms of a corresponding type as evidence, then it is obvious that there can be any number of proofs of a certain statement (as well as terms of a corresponding type). For example, it seems to me that the function above can be proved easier It is also interesting that the β€œsorted list” type I cited is a kind of singleton: each type has one representative. As for the permutation, for one type there can be an infinite number of different terms (for example, you can rearrange the same elements twice so that the lists will not change).

Order on natural numbers

 data β„• : Set where zero : β„• suc : β„• β†’ β„• data _≀_ : β„• β†’ β„• β†’ Set where z≀n : βˆ€ {n} β†’ zero ≀ n s≀s : βˆ€ {mn} (m≀n : m ≀ n) β†’ suc m ≀ suc n decNat : (xy : β„•) β†’ (x ≀ y) ⊎ (y ≀ x) decNat zero y = inj₁ z≀n decNat (suc x) (suc y) with decNat xy ... | inj₁ p = inj₁ (s≀sp) ... | injβ‚‚ p = injβ‚‚ (s≀sp) decNat (suc x) zero = injβ‚‚ z≀n 


Finally, the resolving procedure for determining the order on natural numbers. (Pay attention to how variables are named - all that there is a term without spaces.) The predicate is _≀_ . Two axioms are introduced, one of which says that any number is greater than or equal to zero, and the other that if one number is greater than the other, then the ratio will remain if you add one to them.
It also uses a with construction - but I think its use is very clear.

That's all:)

From myself I will say that it is very interesting to write such programs.

Source: https://habr.com/ru/post/148769/


All Articles