comparison src/GeneralRec.v @ 398:05efde66559d

Get it working in Coq 8.4beta1; use nice coqdoc notation for italics
author Adam Chlipala <adam@chlipala.net>
date Wed, 06 Jun 2012 11:25:13 -0400
parents 31fa03bc0f18
children f1cdae4af393
comparison
equal deleted inserted replaced
397:d62ed7381a0b 398:05efde66559d
18 18
19 (** %\chapter{General Recursion}% *) 19 (** %\chapter{General Recursion}% *)
20 20
21 (** Termination of all programs is a crucial property of Gallina. Non-terminating programs introduce logical inconsistency, where any theorem can be proved with an infinite loop. Coq uses a small set of conservative, syntactic criteria to check termination of all recursive definitions. These criteria are insufficient to support the natural encodings of a variety of important programming idioms. Further, since Coq makes it so convenient to encode mathematics computationally, with functional programs, we may find ourselves wanting to employ more complicated recursion in mathematical definitions. 21 (** Termination of all programs is a crucial property of Gallina. Non-terminating programs introduce logical inconsistency, where any theorem can be proved with an infinite loop. Coq uses a small set of conservative, syntactic criteria to check termination of all recursive definitions. These criteria are insufficient to support the natural encodings of a variety of important programming idioms. Further, since Coq makes it so convenient to encode mathematics computationally, with functional programs, we may find ourselves wanting to employ more complicated recursion in mathematical definitions.
22 22
23 What exactly are the conservative criteria that we run up against? For %\emph{%#<i>#recursive#</i>#%}% definitions, recursive calls are only allowed on %\emph{%#<i>#syntactic subterms#</i>#%}% of the original primary argument, a restriction known as %\index{primitive recursion}\emph{%#<i>#primitive recursion#</i>#%}%. In fact, Coq's handling of reflexive inductive types (those defined in terms of functions returning the same type) gives a bit more flexibility than in traditional primitive recursion, but the term is still applied commonly. In Chapter 5, we saw how %\emph{%#<i>#co-recursive#</i>#%}% definitions are checked against a syntactic guardness condition that guarantees productivity. 23 What exactly are the conservative criteria that we run up against? For _recursive_ definitions, recursive calls are only allowed on _syntactic subterms_ of the original primary argument, a restriction known as %\index{primitive recursion}%_primitive recursion_. In fact, Coq's handling of reflexive inductive types (those defined in terms of functions returning the same type) gives a bit more flexibility than in traditional primitive recursion, but the term is still applied commonly. In Chapter 5, we saw how _co-recursive_ definitions are checked against a syntactic guardness condition that guarantees productivity.
24 24
25 Many natural recursion patterns satisfy neither condition. For instance, there is our simple running example in this chapter, merge sort. We will study three different approaches to more flexible recursion, and the latter two of the approaches will even support definitions that may fail to terminate on certain inputs, without any up-front characterization of which inputs those may be. 25 Many natural recursion patterns satisfy neither condition. For instance, there is our simple running example in this chapter, merge sort. We will study three different approaches to more flexible recursion, and the latter two of the approaches will even support definitions that may fail to terminate on certain inputs, without any up-front characterization of which inputs those may be.
26 26
27 Before proceeding, it is important to note that the problem here is not as fundamental as it may appear. The final example of Chapter 5 demonstrated what is called a %\index{deep embedding}\emph{%#<i>#deep embedding#</i>#%}% of the syntax and semantics of a programming language. That is, we gave a mathematical definition of a language of programs and their meanings. This language clearly admitted non-termination, and we could think of writing all our sophisticated recursive functions with such explicit syntax types. However, in doing so, we forfeit our chance to take advantage of Coq's very good built-in support for reasoning about Gallina programs. We would rather use a %\index{shallow embedding}\emph{%#<i>#shallow embedding#</i>#%}%, where we model informal constructs by encoding them as normal Gallina programs. Each of the three techniques of this chapter follows that style. *) 27 Before proceeding, it is important to note that the problem here is not as fundamental as it may appear. The final example of Chapter 5 demonstrated what is called a %\index{deep embedding}%_deep embedding_ of the syntax and semantics of a programming language. That is, we gave a mathematical definition of a language of programs and their meanings. This language clearly admitted non-termination, and we could think of writing all our sophisticated recursive functions with such explicit syntax types. However, in doing so, we forfeit our chance to take advantage of Coq's very good built-in support for reasoning about Gallina programs. We would rather use a %\index{shallow embedding}%_shallow embedding_, where we model informal constructs by encoding them as normal Gallina programs. Each of the three techniques of this chapter follows that style. *)
28 28
29 29
30 (** * Well-Founded Recursion *) 30 (** * Well-Founded Recursion *)
31 31
32 (** The essence of terminating recursion is that there are no infinite chains of nested recursive calls. This intuition is commonly mapped to the mathematical idea of a %\index{well-founded relation}\emph{%#<i>#well-founded relation#</i>#%}%, and the associated standard technique in Coq is %\index{well-founded recursion}\emph{%#<i>#well-founded recursion#</i>#%}%. The syntactic-subterm relation that Coq applies by default is well-founded, but many cases demand alternate well-founded relations. To demonstrate, let us see where we get stuck on attempting a standard merge sort implementation. *) 32 (** The essence of terminating recursion is that there are no infinite chains of nested recursive calls. This intuition is commonly mapped to the mathematical idea of a %\index{well-founded relation}%_well-founded relation_, and the associated standard technique in Coq is %\index{well-founded recursion}%_well-founded recursion_. The syntactic-subterm relation that Coq applies by default is well-founded, but many cases demand alternate well-founded relations. To demonstrate, let us see where we get stuck on attempting a standard merge sort implementation. *)
33 33
34 Section mergeSort. 34 Section mergeSort.
35 Variable A : Type. 35 Variable A : Type.
36 Variable le : A -> A -> bool. 36 Variable le : A -> A -> bool.
37 (** We have a set equipped with some %``%#"#less-than-or-equal-to#"#%''% test. *) 37 (** We have a set equipped with some %``%#"#less-than-or-equal-to#"#%''% test. *)
88 (** %\vspace{-.15in}% [[ 88 (** %\vspace{-.15in}% [[
89 well_founded = 89 well_founded =
90 fun (A : Type) (R : A -> A -> Prop) => forall a : A, Acc R a 90 fun (A : Type) (R : A -> A -> Prop) => forall a : A, Acc R a
91 ]] 91 ]]
92 92
93 The bulk of the definitional work devolves to the %\index{accessibility relation}\index{Gallina terms!Acc}\emph{%#<i>#accessibility#</i>#%}% relation [Acc], whose definition we may also examine. *) 93 The bulk of the definitional work devolves to the %\index{accessibility relation}\index{Gallina terms!Acc}%_accessibility_ relation [Acc], whose definition we may also examine. *)
94 94
95 Print Acc. 95 Print Acc.
96 (** %\vspace{-.15in}% [[ 96 (** %\vspace{-.15in}% [[
97 Inductive Acc (A : Type) (R : A -> A -> Prop) (x : A) : Prop := 97 Inductive Acc (A : Type) (R : A -> A -> Prop) (x : A) : Prop :=
98 Acc_intro : (forall y : A, R y x -> Acc R y) -> Acc R x 98 Acc_intro : (forall y : A, R y x -> Acc R y) -> Acc R x
160 160
161 Theorem lengthOrder_wf : well_founded lengthOrder. 161 Theorem lengthOrder_wf : well_founded lengthOrder.
162 red; intro; eapply lengthOrder_wf'; eauto. 162 red; intro; eapply lengthOrder_wf'; eauto.
163 Defined. 163 Defined.
164 164
165 (** Notice that we end these proofs with %\index{Vernacular commands!Defined}%[Defined], not [Qed]. Recall that [Defined] marks the theorems as %\emph{transparent}%, so that the details of their proofs may be used during program execution. Why could such details possibly matter for computation? It turns out that [Fix] satisfies the primitive recursion restriction by declaring itself as %\emph{%#<i>#recursive in the structure of [Acc] proofs#</i>#%}%. This is possible because [Acc] proofs follow a predictable inductive structure. We must do work, as in the last theorem's proof, to establish that all elements of a type belong to [Acc], but the automatic unwinding of those proofs during recursion is straightforward. If we ended the proof with [Qed], the proof details would be hidden from computation, in which case the unwinding process would get stuck. 165 (** Notice that we end these proofs with %\index{Vernacular commands!Defined}%[Defined], not [Qed]. Recall that [Defined] marks the theorems as %\emph{transparent}%, so that the details of their proofs may be used during program execution. Why could such details possibly matter for computation? It turns out that [Fix] satisfies the primitive recursion restriction by declaring itself as _recursive in the structure of [Acc] proofs_. This is possible because [Acc] proofs follow a predictable inductive structure. We must do work, as in the last theorem's proof, to establish that all elements of a type belong to [Acc], but the automatic unwinding of those proofs during recursion is straightforward. If we ended the proof with [Qed], the proof details would be hidden from computation, in which case the unwinding process would get stuck.
166 166
167 To justify our two recursive [mergeSort] calls, we will also need to prove that [partition] respects the [lengthOrder] relation. These proofs, too, must be kept transparent, to avoid stuckness of [Fix] evaluation. *) 167 To justify our two recursive [mergeSort] calls, we will also need to prove that [partition] respects the [lengthOrder] relation. These proofs, too, must be kept transparent, to avoid stuckness of [Fix] evaluation. *)
168 168
169 Lemma partition_wf : forall len ls, 2 <= length ls <= len 169 Lemma partition_wf : forall len ls, 2 <= length ls <= len
170 -> let (ls1, ls2) := partition ls in 170 -> let (ls1, ls2) := partition ls in
222 then let lss := partition ls in 222 then let lss := partition ls in
223 merge le (mergeSort le (fst lss)) (mergeSort le (snd lss)) 223 merge le (mergeSort le (fst lss)) (mergeSort le (snd lss))
224 else ls. 224 else ls.
225 intros; apply (Fix_eq (@lengthOrder_wf A) (fun _ => list A)); intros. 225 intros; apply (Fix_eq (@lengthOrder_wf A) (fun _ => list A)); intros.
226 226
227 (** The library theorem [Fix_eq] imposes one more strange subgoal upon us. We must prove that the function body is unable to distinguish between %``%#"#self#"#%''% arguments that map equal inputs to equal outputs. One might think this should be true of any Gallina code, but in fact this general %\index{extensionality}\emph{%#<i>#function extensionality#</i>#%}% property is neither provable nor disprovable within Coq. The type of [Fix_eq] makes clear what we must show manually: *) 227 (** The library theorem [Fix_eq] imposes one more strange subgoal upon us. We must prove that the function body is unable to distinguish between %``%#"#self#"#%''% arguments that map equal inputs to equal outputs. One might think this should be true of any Gallina code, but in fact this general %\index{extensionality}%_function extensionality_ property is neither provable nor disprovable within Coq. The type of [Fix_eq] makes clear what we must show manually: *)
228 228
229 Check Fix_eq. 229 Check Fix_eq.
230 (** %\vspace{-.15in}%[[ 230 (** %\vspace{-.15in}%[[
231 Fix_eq 231 Fix_eq
232 : forall (A : Type) (R : A -> A -> Prop) (Rwf : well_founded R) 232 : forall (A : Type) (R : A -> A -> Prop) (Rwf : well_founded R)
276 Some more recent Coq features provide more convenient syntax for defining recursive functions. Interested readers can consult the Coq manual about the commands %\index{Function}%[Function] and %\index{Program Fixpoint}%[Program Fixpoint]. *) 276 Some more recent Coq features provide more convenient syntax for defining recursive functions. Interested readers can consult the Coq manual about the commands %\index{Function}%[Function] and %\index{Program Fixpoint}%[Program Fixpoint]. *)
277 277
278 278
279 (** * A Non-Termination Monad Inspired by Domain Theory *) 279 (** * A Non-Termination Monad Inspired by Domain Theory *)
280 280
281 (** The key insights of %\index{domain theory}%domain theory%~\cite{WinskelDomains}% inspire the next approach to modeling non-termination. Domain theory is based on %\emph{%#<i>#information orders#</i>#%}% that relate values representing computation results, according to how much information these values convey. For instance, a simple domain might include values %``%#"#the program does not terminate#"#%''% and %``%#"#the program terminates with the answer 5.#"#%''% The former is considered to be an %\emph{%#<i>#approximation#</i>#%}% of the latter, while the latter is %\emph{%#<i>#not#</i>#%}% an approximation of %``%#"#the program terminates with the answer 6.#"#%''% The details of domain theory will not be important in what follows; we merely borrow the notion of an approximation ordering on computation results. 281 (** The key insights of %\index{domain theory}%domain theory%~\cite{WinskelDomains}% inspire the next approach to modeling non-termination. Domain theory is based on _information orders_ that relate values representing computation results, according to how much information these values convey. For instance, a simple domain might include values %``%#"#the program does not terminate#"#%''% and %``%#"#the program terminates with the answer 5.#"#%''% The former is considered to be an _approximation_ of the latter, while the latter is _not_ an approximation of %``%#"#the program terminates with the answer 6.#"#%''% The details of domain theory will not be important in what follows; we merely borrow the notion of an approximation ordering on computation results.
282 282
283 Consider this definition of a type of computations. *) 283 Consider this definition of a type of computations. *)
284 284
285 Section computation. 285 Section computation.
286 Variable A : Type. 286 Variable A : Type.
293 | forall (n : nat) (v : A), 293 | forall (n : nat) (v : A),
294 f n = Some v 294 f n = Some v
295 -> forall (n' : nat), n' >= n 295 -> forall (n' : nat), n' >= n
296 -> f n' = Some v}. 296 -> f n' = Some v}.
297 297
298 (** A computation is fundamentally a function [f] from an %\emph{%#<i>#approximation level#</i>#%}% [n] to an optional result. Intuitively, higher [n] values enable termination in more cases than lower values. A call to [f] may return [None] to indicate that [n] was not high enough to run the computation to completion; higher [n] values may yield [Some]. Further, the proof obligation within the sigma type asserts that [f] is %\emph{%#<i>#monotone#</i>#%}% in an appropriate sense: when some [n] is sufficient to produce termination, so are all higher [n] values, and they all yield the same program result [v]. 298 (** A computation is fundamentally a function [f] from an _approximation level_ [n] to an optional result. Intuitively, higher [n] values enable termination in more cases than lower values. A call to [f] may return [None] to indicate that [n] was not high enough to run the computation to completion; higher [n] values may yield [Some]. Further, the proof obligation within the sigma type asserts that [f] is _monotone_ in an appropriate sense: when some [n] is sufficient to produce termination, so are all higher [n] values, and they all yield the same program result [v].
299 299
300 It is easy to define a relation characterizing when a computation runs to a particular result at a particular approximation level. *) 300 It is easy to define a relation characterizing when a computation runs to a particular result at a particular approximation level. *)
301 301
302 Definition runTo (m : computation) (n : nat) (v : A) := 302 Definition runTo (m : computation) (n : nat) (v : A) :=
303 proj1_sig m n = Some v. 303 proj1_sig m n = Some v.
455 (f : A -> computation B) (g : B -> computation C), 455 (f : A -> computation B) (g : B -> computation C),
456 meq (Bind (Bind m f) g) (Bind m (fun x => Bind (f x) g)). 456 meq (Bind (Bind m f) g) (Bind m (fun x => Bind (f x) g)).
457 run. 457 run.
458 Qed. 458 Qed.
459 459
460 (** Now we come to the piece most directly inspired by domain theory. We want to support general recursive function definitions, but domain theory tells us that not all definitions are reasonable; some fail to be %\emph{%#<i>#continuous#</i>#%}% and thus represent unrealizable computations. To formalize an analogous notion of continuity for our non-termination monad, we write down the approximation relation on computation results that we have had in mind all along. *) 460 (** Now we come to the piece most directly inspired by domain theory. We want to support general recursive function definitions, but domain theory tells us that not all definitions are reasonable; some fail to be _continuous_ and thus represent unrealizable computations. To formalize an analogous notion of continuity for our non-termination monad, we write down the approximation relation on computation results that we have had in mind all along. *)
461 461
462 Section lattice. 462 Section lattice.
463 Variable A : Type. 463 Variable A : Type.
464 464
465 Definition leq (x y : option A) := 465 Definition leq (x y : option A) :=
766 766
767 CoInductive comp (A : Type) : Type := 767 CoInductive comp (A : Type) : Type :=
768 | Ret : A -> comp A 768 | Ret : A -> comp A
769 | Bnd : forall B, comp B -> (B -> comp A) -> comp A. 769 | Bnd : forall B, comp B -> (B -> comp A) -> comp A.
770 770
771 (** This example shows off Coq's support for %\index{recursively non-uniform parameters}\emph{%#<i>#recursively non-uniform parameters#</i>#%}%, as in the case of the parameter [A] declared above, where each constructor's type ends in [comp A], but there is a recursive use of [comp] with a different parameter [B]. Beside that technical wrinkle, we see the simplest possible definition of a monad, via a type whose two constructors are precisely the monad operators. 771 (** This example shows off Coq's support for %\index{recursively non-uniform parameters}%_recursively non-uniform parameters_, as in the case of the parameter [A] declared above, where each constructor's type ends in [comp A], but there is a recursive use of [comp] with a different parameter [B]. Beside that technical wrinkle, we see the simplest possible definition of a monad, via a type whose two constructors are precisely the monad operators.
772 772
773 It is easy to define the semantics of terminating [comp] computations. *) 773 It is easy to define the semantics of terminating [comp] computations. *)
774 774
775 Inductive exec A : comp A -> A -> Prop := 775 Inductive exec A : comp A -> A -> Prop :=
776 | ExecRet : forall x, exec (Ret x) x 776 | ExecRet : forall x, exec (Ret x) x