Introducing Well-founded Recursion
Eric Mertens
Galois Inc
Tech Talk: June 15, 2010
Eric Mertens (Galois Inc)
Introducing Well-founded Recursion
Tech Talk: June 15, 2010
1 / 24
This Talk
Introduction to Agda Implementing Quicksort Dening Relations Building a better recursion Back to Implementing Quicksort
Eric Mertens (Galois Inc)
Introducing Well-founded Recursion
Tech Talk: June 15, 2010
2 / 24
Introduction to Agda
The Agda Programming Language
Agda is a dependently typed functional programming language. Agda is a proof assistant based on intuitionistic type theory. Agda has similar syntax to Haskell.
Eric Mertens (Galois Inc)
Introducing Well-founded Recursion
Tech Talk: June 15, 2010
3 / 24
Introduction to Agda
Programs as Proofs
Types are propositions.
Eric Mertens (Galois Inc)
Introducing Well-founded Recursion
Tech Talk: June 15, 2010
4 / 24
Introduction to Agda
Programs as Proofs
Types are propositions. Inhabited types are true propositions. data : Set where unit :
Eric Mertens (Galois Inc)
Introducing Well-founded Recursion
Tech Talk: June 15, 2010
4 / 24
Introduction to Agda
Programs as Proofs
Types are propositions. Inhabited types are true propositions. data : Set where unit :
Uninhabited types are false propositions. data : Set where
Eric Mertens (Galois Inc)
Introducing Well-founded Recursion
Tech Talk: June 15, 2010
4 / 24
Introduction to Agda
Programs as Proofs
Types are propositions. Inhabited types are true propositions. data : Set where unit :
Uninhabited types are false propositions. data : Set where Implementations are proofs.
Eric Mertens (Galois Inc)
Introducing Well-founded Recursion
Tech Talk: June 15, 2010
4 / 24
Introduction to Agda
The Price of Consistency
Programs must be total.
Eric Mertens (Galois Inc)
Introducing Well-founded Recursion
Tech Talk: June 15, 2010
5 / 24
Introduction to Agda
The Price of Consistency
Programs must be total. head : List (1 2) (1 2) head (x :: xs) = x
Eric Mertens (Galois Inc)
Introducing Well-founded Recursion
Tech Talk: June 15, 2010
5 / 24
Introduction to Agda
The Price of Consistency
Programs must be total. head : List (1 2) (1 2) head (x :: xs) = x
Programs must terminate.
Eric Mertens (Galois Inc)
Introducing Well-founded Recursion
Tech Talk: June 15, 2010
5 / 24
Introduction to Agda
The Price of Consistency
Programs must be total. head : List (1 2) (1 2) head (x :: xs) = x
Programs must terminate. absurd : absurd = absurd
Eric Mertens (Galois Inc)
Introducing Well-founded Recursion
Tech Talk: June 15, 2010
5 / 24
Introduction to Agda
The Termination Checker
Agda uses a termination checking algorithm when loading source les. Structural recursion is supported by the termination checker. Structural recursion allows us to make recursive calls on a structrually smaller argument.
Eric Mertens (Galois Inc)
Introducing Well-founded Recursion
Tech Talk: June 15, 2010
6 / 24
Introduction to Agda
The Termination Checker
Agda uses a termination checking algorithm when loading source les. Structural recursion is supported by the termination checker. Structural recursion allows us to make recursive calls on a structrually smaller argument. Example foldl : {a b : Set} List a (b a b) b b foldl [ ] f z = z foldl (x :: xs) f z = foldl xs f (f z x)
Eric Mertens (Galois Inc)
Introducing Well-founded Recursion
Tech Talk: June 15, 2010
6 / 24
Introduction to Agda
The Termination Checker
Agda uses a termination checking algorithm when loading source les. Structural recursion is supported by the termination checker. Structural recursion allows us to make recursive calls on a structrually smaller argument. Example foldl : {a b : Set} List a (b a b) b b foldl [ ] f z = z foldl (x :: xs) f z = foldl xs f (f z x) But not all recursive functions are structurally recursive...
Eric Mertens (Galois Inc)
Introducing Well-founded Recursion
Tech Talk: June 15, 2010
6 / 24
Introduction to Agda
Additional Termination Checker Features
Agda can nd termination orders across mutually recursive functions.
Eric Mertens (Galois Inc)
Introducing Well-founded Recursion
Tech Talk: June 15, 2010
7 / 24
Introduction to Agda
Additional Termination Checker Features
Agda can nd termination orders across mutually recursive functions. Agda can nd lexicographic termination orders.
Eric Mertens (Galois Inc)
Introducing Well-founded Recursion
Tech Talk: June 15, 2010
7 / 24
Introduction to Agda
Additional Termination Checker Features
Agda can nd termination orders across mutually recursive functions. Agda can nd lexicographic termination orders. Example ack : N N N ack 0 n = 1 ack (suc m) 0 = ack m 1 ack (suc m) (suc n) = ack m (ack (suc m) n)
Eric Mertens (Galois Inc)
Introducing Well-founded Recursion
Tech Talk: June 15, 2010
7 / 24
Introduction to Agda
Additional Termination Checker Features
Agda can nd termination orders across mutually recursive functions. Agda can nd lexicographic termination orders. Example ack : N N N ack 0 n = 1 ack (suc m) 0 = ack m 1 ack (suc m) (suc n) = ack m (ack (suc m) n) Is this enough?
Eric Mertens (Galois Inc)
Introducing Well-founded Recursion
Tech Talk: June 15, 2010
7 / 24
Implementing Quicksort
Introduction to Agda Implementing Quicksort Dening Relations Building a better recursion Back to Implementing Quicksort
Eric Mertens (Galois Inc)
Introducing Well-founded Recursion
Tech Talk: June 15, 2010
8 / 24
Implementing Quicksort
Quicksort in Haskell
Nave functional-programming quicksort quicksort :: (a a Bool) List a List a quicksort p [ ] = [ ] quicksort p (x : xs) = case partition (p x) xs of (small, big) small + [x] + big + + where small = quicksort p small big = quicksort p big
Eric Mertens (Galois Inc)
Introducing Well-founded Recursion
Tech Talk: June 15, 2010
9 / 24
Implementing Quicksort
Quicksort in Haskell
Nave functional-programming quicksort quicksort :: (a a Bool) List a List a quicksort p [ ] = [ ] quicksort p (x : xs) = case partition (p x) xs of (small, big) small + [x] + big + + where small = quicksort p small big = quicksort p big Why does this terminate (on nite lists)?
Eric Mertens (Galois Inc)
Introducing Well-founded Recursion
Tech Talk: June 15, 2010
9 / 24
Implementing Quicksort
Quicksort in Agda
Nave functional-programming quicksort in Agda quicksort : {A : Set} (A A Bool) List A List A quicksort p [ ] = [ ] quicksort p (x :: xs) with partition (p x) xs ... | small, big = small + [x] + big + + where small = quicksort p small big = quicksort p big
Eric Mertens (Galois Inc)
Introducing Well-founded Recursion
Tech Talk: June 15, 2010
10 / 24
Implementing Quicksort
Quicksort in Agda
Nave functional-programming quicksort in Agda quicksort : {A : Set} (A A Bool) List A List A quicksort p [ ] = [ ] quicksort p (x :: xs) with partition (p x) xs ... | small, big = small + [x] + big + + where small = quicksort p small big = quicksort p big The termination checker fails on this function.
Eric Mertens (Galois Inc)
Introducing Well-founded Recursion
Tech Talk: June 15, 2010
10 / 24
Implementing Quicksort
Well-founded Recursion
Recursive calls are on "smaller" arguments. No intinte descending chains of recursive calls; we always reach a smallest element. We can capture this relation between elements in Agda.
Eric Mertens (Galois Inc)
Introducing Well-founded Recursion
Tech Talk: June 15, 2010
11 / 24
Implementing Quicksort
Well-founded Relations
A relation is well-founded if it contains no innite descending chains.
Eric Mertens (Galois Inc)
Introducing Well-founded Recursion
Tech Talk: June 15, 2010
12 / 24
Implementing Quicksort
Well-founded Relations
A relation is well-founded if it contains no innite descending chains. Example: "Less than" on natural numbers (<).
Eric Mertens (Galois Inc)
Introducing Well-founded Recursion
Tech Talk: June 15, 2010
12 / 24
Implementing Quicksort
Well-founded Relations
A relation is well-founded if it contains no innite descending chains. Example: "Less than" on natural numbers (<). 0 < 1 < 2 < 5 < 8 < 10
Eric Mertens (Galois Inc)
Introducing Well-founded Recursion
Tech Talk: June 15, 2010
12 / 24
Implementing Quicksort
Well-founded Relations
A relation is well-founded if it contains no innite descending chains. Example: "Less than" on natural numbers (<). 0 < 1 < 2 < 5 < 8 < 10 Example: "Proper subset" on sets ().
Eric Mertens (Galois Inc)
Introducing Well-founded Recursion
Tech Talk: June 15, 2010
12 / 24
Implementing Quicksort
Well-founded Relations
A relation is well-founded if it contains no innite descending chains. Example: "Less than" on natural numbers (<). 0 < 1 < 2 < 5 < 8 < 10 Example: "Proper subset" on sets (). {} {2} {1,2,5} {1,2,3,4,5}
Eric Mertens (Galois Inc)
Introducing Well-founded Recursion
Tech Talk: June 15, 2010
12 / 24
Implementing Quicksort
Well-founded Relations
A relation is well-founded if it contains no innite descending chains. Example: "Less than" on natural numbers (<). 0 < 1 < 2 < 5 < 8 < 10 Example: "Proper subset" on sets (). {} {2} {1,2,5} {1,2,3,4,5} False example: "Less than or equal to" on natural numbers ( ).
Eric Mertens (Galois Inc)
Introducing Well-founded Recursion
Tech Talk: June 15, 2010
12 / 24
Implementing Quicksort
Well-founded Relations
A relation is well-founded if it contains no innite descending chains. Example: "Less than" on natural numbers (<). 0 < 1 < 2 < 5 < 8 < 10 Example: "Proper subset" on sets (). {} {2} {1,2,5} {1,2,3,4,5} False example: "Less than or equal to" on natural numbers ( ). 42 42 42
Eric Mertens (Galois Inc)
Introducing Well-founded Recursion
Tech Talk: June 15, 2010
12 / 24
Dening Relations
Introduction to Agda Implementing Quicksort Dening Relations Building a better recursion Back to Implementing Quicksort
Eric Mertens (Galois Inc)
Introducing Well-founded Recursion
Tech Talk: June 15, 2010
13 / 24
Dening Relations
Relations in Agda
Characterizing relations: Rel : Set Set1 Rel A = A A Set
Eric Mertens (Galois Inc)
Introducing Well-founded Recursion
Tech Talk: June 15, 2010
14 / 24
Dening Relations
Relations in Agda
Characterizing relations: Rel : Set Set1 Rel A = A A Set Dening a new relation (inductively dened type family): data _<_ (m : N) : N Set where <-base : m < suc m <-step : {n : N} m < n m < suc n
Eric Mertens (Galois Inc)
Introducing Well-founded Recursion
Tech Talk: June 15, 2010
14 / 24
Dening Relations
Relations in Agda
Characterizing relations: Rel : Set Set1 Rel A = A A Set Dening a new relation (inductively dened type family): data _<_ (m : N) : N Set where <-base : m < suc m <-step : {n : N} m < n m < suc n Dening a negation: _ _ : Rel N a b = a<b
Eric Mertens (Galois Inc) Introducing Well-founded Recursion Tech Talk: June 15, 2010 14 / 24
Dening Relations
Examples using relations
Inhabiting a relation: example1 : 3 < 5 example1 = ? Goal: 3 < 5
Eric Mertens (Galois Inc)
Introducing Well-founded Recursion
Tech Talk: June 15, 2010
15 / 24
Dening Relations
Examples using relations
Inhabiting a relation: example1 : 3 < 5 example1 = <-step ? Goal: 3 < 4
Eric Mertens (Galois Inc)
Introducing Well-founded Recursion
Tech Talk: June 15, 2010
15 / 24
Dening Relations
Examples using relations
Inhabiting a relation: example1 : 3 < 5 example1 = <-step <-base Done
Eric Mertens (Galois Inc)
Introducing Well-founded Recursion
Tech Talk: June 15, 2010
15 / 24
Dening Relations
Examples using relations
Inhabiting a relation: example1 : 3 < 5 example1 = <-step <-base
Uninhabited relation: example2 : 5 example2 x x: 5<2 2
Eric Mertens (Galois Inc)
Introducing Well-founded Recursion
Tech Talk: June 15, 2010
15 / 24
Dening Relations
Examples using relations
Inhabiting a relation: example1 : 3 < 5 example1 = <-step <-base
Uninhabited relation: example2 : 5 2 example2 (<-step x) x: 5<1
Eric Mertens (Galois Inc)
Introducing Well-founded Recursion
Tech Talk: June 15, 2010
15 / 24
Dening Relations
Examples using relations
Inhabiting a relation: example1 : 3 < 5 example1 = <-step <-base
Uninhabited relation: example2 : 5 2 example2 (<-step (<-step x)) x: 5<0
Eric Mertens (Galois Inc)
Introducing Well-founded Recursion
Tech Talk: June 15, 2010
15 / 24
Dening Relations
Examples using relations
Inhabiting a relation: example1 : 3 < 5 example1 = <-step <-base
Uninhabited relation: example2 : 5 2 example2 (<-step (<-step ())) Done
Eric Mertens (Galois Inc)
Introducing Well-founded Recursion
Tech Talk: June 15, 2010
15 / 24
Building a better recursion
Introduction to Agda Implementing Quicksort Dening Relations Building a better recursion Back to Implementing Quicksort
Eric Mertens (Galois Inc)
Introducing Well-founded Recursion
Tech Talk: June 15, 2010
16 / 24
Building a better recursion
Accessibility
We need a way to encode what it means for a relation to be well-founded.
Eric Mertens (Galois Inc)
Introducing Well-founded Recursion
Tech Talk: June 15, 2010
17 / 24
Building a better recursion
Accessibility
We need a way to encode what it means for a relation to be well-founded. An element, x, of a set, A, is "accessible" with respect to a relation,<, i all of the elements, y, are less-than x are accessible.
module WF {A : Set} (_<_ : Rel A) where data Acc (x : A) : Set where acc : ( y y < x Acc y) Acc x
Eric Mertens (Galois Inc)
Introducing Well-founded Recursion
Tech Talk: June 15, 2010
17 / 24
Building a better recursion
Accessibility
We need a way to encode what it means for a relation to be well-founded. An element, x, of a set, A, is "accessible" with respect to a relation,<, i all of the elements, y, are less-than x are accessible. A relation is well-founded i all elements in the set are accessible. module WF {A : Set} (_<_ : Rel A) where data Acc (x : A) : Set where acc : ( y y < x Acc y) Acc x Well-founded : Set Well-founded = x Acc x
Eric Mertens (Galois Inc)
Introducing Well-founded Recursion
Tech Talk: June 15, 2010
17 / 24
Building a better recursion
The less-than relation on N is well-founded
We implement this with structural recursion. <-N-wf : Well-founded _<_ <-N-wf x = acc (aux x) where aux : x y y < x Acc _<_ y aux . (suc y) y <-base = <-N-wf y aux . (suc x) y (<-step {x} y<x) = aux x y y<x
Eric Mertens (Galois Inc)
Introducing Well-founded Recursion
Tech Talk: June 15, 2010
18 / 24
Building a better recursion
The less-than relation on N is well-founded
We implement this with structural recursion. <-N-wf : Well-founded _<_ <-N-wf x = acc (aux x) where aux : x y y < x Acc _<_ y aux . (suc y) y <-base = <-N-wf y aux . (suc x) y (<-step {x} y<x) = aux x y y<x This is rather complicated; lets reuse it!
Eric Mertens (Galois Inc)
Introducing Well-founded Recursion
Tech Talk: June 15, 2010
18 / 24
Building a better recursion
Building new well-founded relations
Lets build new well-founded relations from old ones.
Eric Mertens (Galois Inc)
Introducing Well-founded Recursion
Tech Talk: June 15, 2010
19 / 24
Building a better recursion
Building new well-founded relations
Lets build new well-founded relations from old ones. module Inverse-image-Well-founded {A B} (_<_ : Rel B) (f : A B) where _ _ : Rel A ii-acc : {x} Acc _<_ (f x) Acc _ _ x ii-wf : Well-founded _<_ Well-founded _ _
Eric Mertens (Galois Inc)
Introducing Well-founded Recursion
Tech Talk: June 15, 2010
19 / 24
Building a better recursion
Building new well-founded relations
Lets build new well-founded relations from old ones. module Inverse-image-Well-founded {A B} (_<_ : Rel B) (f : A B) where _ _ : Rel A x y = fx<fy ii-acc : {x} Acc _<_ (f x) Acc _ _ x ii-wf : Well-founded _<_ Well-founded _ _
Eric Mertens (Galois Inc)
Introducing Well-founded Recursion
Tech Talk: June 15, 2010
19 / 24
Building a better recursion
Building new well-founded relations
Lets build new well-founded relations from old ones. module Inverse-image-Well-founded {A B} (_<_ : Rel B) (f : A B) where _ _ : Rel A x y = fx<fy ii-acc : {x} Acc _<_ (f x) Acc _ _ x ii-acc (acc g) = acc ( y fy<fx ii-acc (g (f y) fy<fx)) ii-wf : Well-founded _<_ Well-founded _ _
Eric Mertens (Galois Inc)
Introducing Well-founded Recursion
Tech Talk: June 15, 2010
19 / 24
Building a better recursion
Building new well-founded relations
Lets build new well-founded relations from old ones. module Inverse-image-Well-founded {A B} (_<_ : Rel B) (f : A B) where _ _ : Rel A x y = fx<fy ii-acc : {x} Acc _<_ (f x) Acc _ _ x ii-acc (acc g) = acc ( y fy<fx ii-acc (g (f y) fy<fx)) ii-wf : Well-founded _<_ Well-founded _ _ ii-wf wf x = ii-acc (wf (f x))
Eric Mertens (Galois Inc)
Introducing Well-founded Recursion
Tech Talk: June 15, 2010
19 / 24
Building a better recursion
Shorter lists
Lets instantiate this module for our quicksort case. _<_ : Rel N length : List A N _ _ : Rel (List A) module <-on-length-Well-founded {A} where open Inverse-image-Well-founded {List A} _<_ length public wf : Well-founded _ _ wf = ii-wf <-N-wf
Eric Mertens (Galois Inc)
Introducing Well-founded Recursion
Tech Talk: June 15, 2010
20 / 24
Back to Implementing Quicksort
Introduction to Agda Implementing Quicksort Dening Relations Building a better recursion Back to Implementing Quicksort
Eric Mertens (Galois Inc)
Introducing Well-founded Recursion
Tech Talk: June 15, 2010
21 / 24
Back to Implementing Quicksort
Partitioned lists dont grow!
Now we show that partition does not make lists longer. module PartitionLemma {A} where _ _ : Rel (List A) x y = length x < (1 + length y) partition-size : (p : A Bool) (xs : List A) proj1 (partition p xs) xs proj2 (partition p xs) xs
Eric Mertens (Galois Inc)
Introducing Well-founded Recursion
Tech Talk: June 15, 2010
22 / 24
Back to Implementing Quicksort
Partitioned lists dont grow!
Now we show that partition does not make lists longer. module PartitionLemma {A} where _ _ : Rel (List A) x y = length x < (1 + length y) partition-size : (p : A Bool) (xs : List A) proj1 (partition p xs) xs proj2 (partition p xs) xs partition-size p [ ] = <-base, <-base partition-size p (x :: xs) with p x | partition p xs | partition-size p xs ... | true | as, bs | as-size, bs-size = s<s as-size, <-step bs-size ... | false | as, bs | as-size, bs-size = <-step as-size, s<s bs-size
Eric Mertens (Galois Inc) Introducing Well-founded Recursion Tech Talk: June 15, 2010 22 / 24
Back to Implementing Quicksort
Quicksort take two
module Quick {A} (p : A A Bool) where open <-on-length-Well-founded; open PartitionLemma quicksort : (xs : List A) List A
quicksort : List A List A quicksort xs = quicksort xs
Eric Mertens (Galois Inc) Introducing Well-founded Recursion Tech Talk: June 15, 2010 23 / 24
Back to Implementing Quicksort
Quicksort take two
module Quick {A} (p : A A Bool) where open <-on-length-Well-founded; open PartitionLemma quicksort : (xs : List A) quicksort [ ] = [ ] quicksort (x :: xs) with partition (p x) xs ... | small, big where small = quicksort small big = quicksort big quicksort : List A List A quicksort xs = quicksort xs
Eric Mertens (Galois Inc) Introducing Well-founded Recursion Tech Talk: June 15, 2010 23 / 24
List A
= small + [x] + big + +
Back to Implementing Quicksort
Quicksort take two
module Quick {A} (p : A A Bool) where open <-on-length-Well-founded; open PartitionLemma quicksort : (xs : List A) Acc _ _ xs List A quicksort [ ] = [ ] quicksort (x :: xs) (acc g) with partition (p x) xs | partition-size (p x) xs ... | small, big | small-size, big-size = small + [x] + big + + where small = quicksort small (g small small-size) big = quicksort big (g big big-size) quicksort : List A List A quicksort xs = quicksort xs (wf xs)
Eric Mertens (Galois Inc) Introducing Well-founded Recursion Tech Talk: June 15, 2010 23 / 24
Back to Implementing Quicksort
Other techniques for building well-founded relations
The subrelation of a well-founded relation is well-founded. The transitive closure of a well-founded relation is well-founded. The lexicographic product of a well-founded relation is well-founded.
Eric Mertens (Galois Inc)
Introducing Well-founded Recursion
Tech Talk: June 15, 2010
24 / 24