comparison src/GeneralRec.v @ 404:f1cdae4af393

Typesetting pass over GeneralRec
author Adam Chlipala <adam@chlipala.net>
date Fri, 08 Jun 2012 13:59:41 -0400
parents 05efde66559d
children f83664d817ce
comparison
equal deleted inserted replaced
403:1edeec5d5d0c 404:f1cdae4af393
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 _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. 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}%_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. *) 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}%_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. *) 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}%_accessibility_ 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
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}%_function extensionality_ 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)
745 Now consider another very similar definition, this time of a Fibonacci number funtion. *) 745 Now consider another very similar definition, this time of a Fibonacci number funtion. *)
746 746
747 Notation "x <- m1 ; m2" := 747 Notation "x <- m1 ; m2" :=
748 (TBind m1 (fun x => m2)) (right associativity, at level 70). 748 (TBind m1 (fun x => m2)) (right associativity, at level 70).
749 749
750 (* begin hide *)
751 Definition fib := 0.
752 (* end hide *)
753
750 (** %\vspace{-.15in}%[[ 754 (** %\vspace{-.15in}%[[
751 CoFixpoint fib (n : nat) : thunk nat := 755 CoFixpoint fib (n : nat) : thunk nat :=
752 match n with 756 match n with
753 | 0 => Answer 1 757 | 0 => Answer 1
754 | 1 => Answer 1 758 | 1 => Answer 1
766 770
767 CoInductive comp (A : Type) : Type := 771 CoInductive comp (A : Type) : Type :=
768 | Ret : A -> comp A 772 | Ret : A -> comp A
769 | Bnd : forall B, comp B -> (B -> comp A) -> comp A. 773 | Bnd : forall B, comp B -> (B -> comp A) -> comp A.
770 774
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. 775 (** 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 776
773 It is easy to define the semantics of terminating [comp] computations. *) 777 It is easy to define the semantics of terminating [comp] computations. *)
774 778
775 Inductive exec A : comp A -> A -> Prop := 779 Inductive exec A : comp A -> A -> Prop :=
776 | ExecRet : forall x, exec (Ret x) x 780 | ExecRet : forall x, exec (Ret x) x