insertion sort: fun insert(e:int, l:int list):int list = case l of [] => [e] | x::xs => if (e < x) then e::l else x::(insert (e,xs)) fun isort' (l1: int list, l2:int list) = case l1 of [] => l2 | x::xs => isort'(xs, insert(x, l2)) fun isort(l:int list) = isort'(l, []) The code above is a version of insertion sort, and below we will attempt to prove that isort works for all integer list. To prove this, we will first prove that 1) insert(e,l) returns a sorted list that contains all the elements of l and e, and 2) that isort'(l1, l2) returns a sorted list containing all the elements lf l1 and l2. In the contex of the proof, we will say that the definition of sorted is the following: for a non-nil list x::xs, for all elements e being members of xs, x <= e and xs is sorted. The nil list is considered sorted. First, the proof for insert. Proof by indution on length of l, assume that l is a sorted list: P(n) = for a sorted list l of length n and any element e, insert(e,l) returns a sorted list l' which contains all the elements of l and also contains n base case: length(l) = 0, by definition of list, the only list with length = to 0 is the empty(nil) list. Therefore, insert(n, []) => (evaluation of function application) case [] of [] => [n] | x::xs => ... => (pattern matching) [n] [n] contains all elements of [] and n, and is also sorted. Therefore, the base case holds. IH: P(n) true for n = k, k > 0. And therefore we have a sorted list l' s.t. length(l') = n, and that insert(e,l') => l'' s.t. l'' is sorted and contains all the elements in l' and also includes e. IS: We now want to prove that P(n) holds for for n=k+1. From the definition of the list, we can say that for a list l of length k+1, we can say that l == h::tl, where length(tl) = n. Now we evaluate as follows: insert(e, l) => (function evaluation and replacing l with h::tl) case h::tl of [] => [e] | x::xs => if (e < x) then n::l else x::(insert(e,xs)) => (pattern matching) if (e < h) then e::l else h::(insert(e,tl)) Now we have two possible results that depend on the value of the expression "e < h", which can have two values, true and false. If e < h = true, then insert(e,l) = e::l. since l is sorted and e < h, e is less than all the elements in l. Therefore, the list e::l is a sorted list and P(n+1) holds for this branch. If e < h = false, then insert(e,l) = h::(insert(e,tl)). Since h::tl is a sorted list by assumption, we know that 1) xs is a sorted list, and 2) that h < all elements in tl. Since h is also < e, then the list h::(insert(e,tl)) is sorted iff insert(e,tl) returns a sorted list. And since length(tl) = n, by IH insert(e,tl) returns a sorted list that contains all the elements of tl and e. Therefore, we can say that h::(insert(e,tl)) is a sorted list that contains all the elements of h::tl and e, and therefore P(n+1) holds for this branch. Since P(n+1) holds for all branches of evaluation, we can therefore say that P(n) holds for all n > 0. Proving isort' works: fun isort' (l1: int list, l2:int list) = case l1 of [] => l2 | x::xs => isort'(xs, insert(x, l2)) We will now prove by induction on the length of l1 that isort' works, or more formally, we will prove the following property: P(n) = for a list l1 of length n, and an sorted list l2 of arbitrary length, isort'(l1, l2) = l, where l is sorted and contains all the elements of l1 and l2. As shown in P(n), we will be inducting on the length of the list l1. Base case: n = 0, again by definition of lists if length(l) = 0 then l is the empty(nil) list. l2 is an arbitrary sorted list. isort' ([], l2) => (evaluation of function application) case [] of [] => l2 | x::xs => isort'(xs, insert(x, l2)) => (pattern matching) l2 l2 is a sorted list by assumption, and also contains all the elements of l2 and [], therefore P(0) holds, and we have proven the base case. IH: P(n) holds for n = k, k > 0. And therefore we have a list l1 of length k, and an sorted list l2 of arbitrary length, isort'(l1, l2) = l, where l is sorted and contains all the elements of l1 and l2. IS: We now want to prove that P(n) holds for for n=k+1. From the definition of the list, we can say that for a list l1 of length k+1, we can say that l1 == h::tl, where length(tl) = n. We can also say that we have an arbitrary sorted list l2. isort'(l1, l2) => (evaluation and replacing l1 with h::tl) case h::tl of [] => l2 | x::xs => isort'(xs, insert(x, l2)) => (pattern matching) isort'(tl, insert(h, l2)) => (lemma for insert, see (a)) isort'(tl, l') (a) We can use the insert lemma here that we proved above because we know that l2 is a sorted list, and so we can say that insert(h,l2) returns a list l' which contains all the elements of h and l2. We know that length(tl) = n, and so by the IH isort'(tl, l') = l'', where l'' is a sorted list containing all the elements of tl and l'. l' contains all the elements of h and l2, and so we can say that l'' contains all the elements of h::tl and l2. This proves P(n+1), and so we can say that P(n) holds for all n > 0. We have now proven that insert works, and using that proved that isort' works. Using the isort' lemma, we will now prove that isort works. fun isort(l:int list) = isort'(l, []) We wish to prove that isort(l) = l', where l' is a sorted list and contains all the elements of l. We don't need to do induction here, as we can prove correctness directly. For arbitrary l, we can step the evaluation as follows: isort(l) => (evaluation) isort'(l, []) And since we know that isort'(l, []) = l' and l' is a sorted list containing all the elements of l and [] (by lemma), we can say that isort(l) returns a sorted list l' which contains all the elements of l.