comparison src/DataStruct.v @ 113:ccab8a30c05e

Templatize DataStruct
author Adam Chlipala <adamc@hcoop.net>
date Tue, 14 Oct 2008 13:05:43 -0400
parents 623478074c2f
children f6eb1ed8048c
comparison
equal deleted inserted replaced
112:623478074c2f 113:ccab8a30c05e
32 | Nil : ilist O 32 | Nil : ilist O
33 | Cons : forall n, A -> ilist n -> ilist (S n). 33 | Cons : forall n, A -> ilist n -> ilist (S n).
34 34
35 (** We might like to have a certified function for selecting an element of an [ilist] by position. We could do this using subset types and explicit manipulation of proofs, but dependent types let us do it more directly. It is helpful to define a type family [index], where [index n] is isomorphic to [{m : nat | m < n}]. Such a type family is also often called [Fin] or similar, standing for "finite." *) 35 (** We might like to have a certified function for selecting an element of an [ilist] by position. We could do this using subset types and explicit manipulation of proofs, but dependent types let us do it more directly. It is helpful to define a type family [index], where [index n] is isomorphic to [{m : nat | m < n}]. Such a type family is also often called [Fin] or similar, standing for "finite." *)
36 36
37 (* EX: Define a function [get] for extracting an [ilist] element by position. *)
38
39 (* begin thide *)
37 Inductive index : nat -> Set := 40 Inductive index : nat -> Set :=
38 | First : forall n, index (S n) 41 | First : forall n, index (S n)
39 | Next : forall n, index n -> index (S n). 42 | Next : forall n, index n -> index (S n).
40 43
41 (** [index] essentially makes a more richly-typed copy of the natural numbers. Every element is a [First] iterated through applying [Next] a number of times that indicates which number is being selected. 44 (** [index] essentially makes a more richly-typed copy of the natural numbers. Every element is a [First] iterated through applying [Next] a number of times that indicates which number is being selected.
109 match idx in index n' return (index (pred n') -> A) -> A with 112 match idx in index n' return (index (pred n') -> A) -> A with
110 | First _ => fun _ => x 113 | First _ => fun _ => x
111 | Next _ idx' => fun get_ls' => get_ls' idx' 114 | Next _ idx' => fun get_ls' => get_ls' idx'
112 end (get ls') 115 end (get ls')
113 end. 116 end.
117 (* end thide *)
114 End ilist. 118 End ilist.
115 119
116 Implicit Arguments Nil [A]. 120 Implicit Arguments Nil [A].
121 (* begin thide *)
117 Implicit Arguments First [n]. 122 Implicit Arguments First [n].
123 (* end thide *)
118 124
119 (** A few examples show how to make use of these definitions. *) 125 (** A few examples show how to make use of these definitions. *)
120 126
121 Check Cons 0 (Cons 1 (Cons 2 Nil)). 127 Check Cons 0 (Cons 1 (Cons 2 Nil)).
122 (** [[ 128 (** [[
123 129
124 Cons 0 (Cons 1 (Cons 2 Nil)) 130 Cons 0 (Cons 1 (Cons 2 Nil))
125 : ilist nat 3 131 : ilist nat 3
126 ]] *) 132 ]] *)
133 (* begin thide *)
127 Eval simpl in get (Cons 0 (Cons 1 (Cons 2 Nil))) First. 134 Eval simpl in get (Cons 0 (Cons 1 (Cons 2 Nil))) First.
128 (** [[ 135 (** [[
129 136
130 = 0 137 = 0
131 : nat 138 : nat
140 (** [[ 147 (** [[
141 148
142 = 2 149 = 2
143 : nat 150 : nat
144 ]] *) 151 ]] *)
152 (* end thide *)
145 153
146 (** Our [get] function is also quite easy to reason about. We show how with a short example about an analogue to the list [map] function. *) 154 (** Our [get] function is also quite easy to reason about. We show how with a short example about an analogue to the list [map] function. *)
147 155
148 Section ilist_map. 156 Section ilist_map.
149 Variables A B : Set. 157 Variables A B : Set.
157 165
158 (** It is easy to prove that [get] "distributes over" [imap] calls. The only tricky bit is remembering to use the [dep_destruct] tactic in place of plain [destruct] when faced with a baffling tactic error message. *) 166 (** It is easy to prove that [get] "distributes over" [imap] calls. The only tricky bit is remembering to use the [dep_destruct] tactic in place of plain [destruct] when faced with a baffling tactic error message. *)
159 167
160 Theorem get_imap : forall n (idx : index n) (ls : ilist A n), 168 Theorem get_imap : forall n (idx : index n) (ls : ilist A n),
161 get (imap ls) idx = f (get ls idx). 169 get (imap ls) idx = f (get ls idx).
170 (* begin thide *)
162 induction ls; dep_destruct idx; crush. 171 induction ls; dep_destruct idx; crush.
163 Qed. 172 Qed.
173 (* end thide *)
164 End ilist_map. 174 End ilist_map.
165 175
166 176
167 (** * Heterogeneous Lists *) 177 (** * Heterogeneous Lists *)
168 178
170 180
171 Section hlist. 181 Section hlist.
172 Variable A : Type. 182 Variable A : Type.
173 Variable B : A -> Type. 183 Variable B : A -> Type.
174 184
185 (* EX: Define a type [hlist] indexed by a [list A], where the type of each element is determined by running [B] on the corresponding element of the index list. *)
186
175 (** We parameterize our heterogeneous lists by a type [A] and an [A]-indexed type [B]. *) 187 (** We parameterize our heterogeneous lists by a type [A] and an [A]-indexed type [B]. *)
176 188
189 (* begin thide *)
177 Inductive hlist : list A -> Type := 190 Inductive hlist : list A -> Type :=
178 | MNil : hlist nil 191 | MNil : hlist nil
179 | MCons : forall (x : A) (ls : list A), B x -> hlist ls -> hlist (x :: ls). 192 | MCons : forall (x : A) (ls : list A), B x -> hlist ls -> hlist (x :: ls).
180 193
181 (** We can implement a variant of the last section's [get] function for [hlist]s. To get the dependent typing to work out, we will need to index our element selectors by the types of data that they point to. *) 194 (** We can implement a variant of the last section's [get] function for [hlist]s. To get the dependent typing to work out, we will need to index our element selectors by the types of data that they point to. *)
182 195
196 (* end thide *)
197 (* EX: Define an analogue to [get] for [hlist]s. *)
198
199 (* begin thide *)
183 Variable elm : A. 200 Variable elm : A.
184 201
185 Inductive member : list A -> Type := 202 Inductive member : list A -> Type :=
186 | MFirst : forall ls, member (elm :: ls) 203 | MFirst : forall ls, member (elm :: ls)
187 | MNext : forall x ls, member ls -> member (x :: ls). 204 | MNext : forall x ls, member ls -> member (x :: ls).
208 end) with 225 end) with
209 | MFirst _ => fun x _ => x 226 | MFirst _ => fun x _ => x
210 | MNext _ _ mem' => fun _ get_mls' => get_mls' mem' 227 | MNext _ _ mem' => fun _ get_mls' => get_mls' mem'
211 end x (hget mls') 228 end x (hget mls')
212 end. 229 end.
230 (* end thide *)
213 End hlist. 231 End hlist.
214 232
233 (* begin thide *)
215 Implicit Arguments MNil [A B]. 234 Implicit Arguments MNil [A B].
216 Implicit Arguments MCons [A B x ls]. 235 Implicit Arguments MCons [A B x ls].
217 236
218 Implicit Arguments MFirst [A elm ls]. 237 Implicit Arguments MFirst [A elm ls].
219 Implicit Arguments MNext [A elm x ls]. 238 Implicit Arguments MNext [A elm x ls].
239 (* end thide *)
220 240
221 (** By putting the parameters [A] and [B] in [Type], we allow some very higher-order uses. For instance, one use of [hlist] is for the simple heterogeneous lists that we referred to earlier. *) 241 (** By putting the parameters [A] and [B] in [Type], we allow some very higher-order uses. For instance, one use of [hlist] is for the simple heterogeneous lists that we referred to earlier. *)
222 242
223 Definition someTypes : list Set := nat :: bool :: nil. 243 Definition someTypes : list Set := nat :: bool :: nil.
244
245 (* begin thide *)
224 246
225 Example someValues : hlist (fun T : Set => T) someTypes := 247 Example someValues : hlist (fun T : Set => T) someTypes :=
226 MCons 5 (MCons true MNil). 248 MCons 5 (MCons true MNil).
227 249
228 Eval simpl in hget someValues MFirst. 250 Eval simpl in hget someValues MFirst.
240 262
241 (** We can also build indexed lists of pairs in this way. *) 263 (** We can also build indexed lists of pairs in this way. *)
242 264
243 Example somePairs : hlist (fun T : Set => T * T)%type someTypes := 265 Example somePairs : hlist (fun T : Set => T * T)%type someTypes :=
244 MCons (1, 2) (MCons (true, false) MNil). 266 MCons (1, 2) (MCons (true, false) MNil).
267
268 (* end thide *)
269
245 270
246 (** ** A Lambda Calculus Interpreter *) 271 (** ** A Lambda Calculus Interpreter *)
247 272
248 (** Heterogeneous lists are very useful in implementing interpreters for functional programming languages. Using the types and operations we have already defined, it is trivial to write an interpreter for simply-typed lambda calculus. Our interpreter can alternatively be thought of as a denotational semantics. 273 (** Heterogeneous lists are very useful in implementing interpreters for functional programming languages. Using the types and operations we have already defined, it is trivial to write an interpreter for simply-typed lambda calculus. Our interpreter can alternatively be thought of as a denotational semantics.
249 274
256 (** Now we can define a type family for expressions. An [exp ts t] will stand for an expression that has type [t] and whose free variables have types in the list [ts]. We effectively use the de Bruijn variable representation, which we will discuss in more detail in later chapters. Variables are represented as [member] values; that is, a variable is more or less a constructive proof that a particular type is found in the type environment. *) 281 (** Now we can define a type family for expressions. An [exp ts t] will stand for an expression that has type [t] and whose free variables have types in the list [ts]. We effectively use the de Bruijn variable representation, which we will discuss in more detail in later chapters. Variables are represented as [member] values; that is, a variable is more or less a constructive proof that a particular type is found in the type environment. *)
257 282
258 Inductive exp : list type -> type -> Set := 283 Inductive exp : list type -> type -> Set :=
259 | Const : forall ts, exp ts Unit 284 | Const : forall ts, exp ts Unit
260 285
286 (* begin thide *)
261 | Var : forall ts t, member t ts -> exp ts t 287 | Var : forall ts t, member t ts -> exp ts t
262 | App : forall ts dom ran, exp ts (Arrow dom ran) -> exp ts dom -> exp ts ran 288 | App : forall ts dom ran, exp ts (Arrow dom ran) -> exp ts dom -> exp ts ran
263 | Abs : forall ts dom ran, exp (dom :: ts) ran -> exp ts (Arrow dom ran). 289 | Abs : forall ts dom ran, exp (dom :: ts) ran -> exp ts (Arrow dom ran).
290 (* end thide *)
264 291
265 Implicit Arguments Const [ts]. 292 Implicit Arguments Const [ts].
266 293
267 (** We write a simple recursive function to translate [type]s into [Set]s. *) 294 (** We write a simple recursive function to translate [type]s into [Set]s. *)
268 295
272 | Arrow t1 t2 => typeDenote t1 -> typeDenote t2 299 | Arrow t1 t2 => typeDenote t1 -> typeDenote t2
273 end. 300 end.
274 301
275 (** Now it is straightforward to write an expression interpreter. The type of the function, [expDenote], tells us that we translate expressions into functions from properly-typed environments to final values. An environment for a free variable list [ts] is simply a [hlist typeDenote ts]. That is, for each free variable, the heterogeneous list that is the environment must have a value of the variable's associated type. We use [hget] to implement the [Var] case, and we use [MCons] to extend the environment in the [Abs] case. *) 302 (** Now it is straightforward to write an expression interpreter. The type of the function, [expDenote], tells us that we translate expressions into functions from properly-typed environments to final values. An environment for a free variable list [ts] is simply a [hlist typeDenote ts]. That is, for each free variable, the heterogeneous list that is the environment must have a value of the variable's associated type. We use [hget] to implement the [Var] case, and we use [MCons] to extend the environment in the [Abs] case. *)
276 303
304 (* EX: Define an interpreter for [exp]s. *)
305
306 (* begin thide *)
277 Fixpoint expDenote ts t (e : exp ts t) {struct e} : hlist typeDenote ts -> typeDenote t := 307 Fixpoint expDenote ts t (e : exp ts t) {struct e} : hlist typeDenote ts -> typeDenote t :=
278 match e in exp ts t return hlist typeDenote ts -> typeDenote t with 308 match e in exp ts t return hlist typeDenote ts -> typeDenote t with
279 | Const _ => fun _ => tt 309 | Const _ => fun _ => tt
280 310
281 | Var _ _ mem => fun s => hget s mem 311 | Var _ _ mem => fun s => hget s mem
315 345
316 = tt 346 = tt
317 : typeDenote Unit 347 : typeDenote Unit
318 ]] *) 348 ]] *)
319 349
350 (* end thide *)
351
320 (** We are starting to develop the tools behind dependent typing's amazing advantage over alternative approaches in several important areas. Here, we have implemented complete syntax, typing rules, and evaluation semantics for simply-typed lambda calculus without even needing to define a syntactic substitution operation. We did it all without a single line of proof, and our implementation is manifestly executable. In a later chapter, we will meet other, more common approaches to language formalization. Such approaches often state and prove explicit theorems about type safety of languages. In the above example, we got type safety, termination, and other meta-theorems for free, by reduction to CIC, which we know has those properties. *) 352 (** We are starting to develop the tools behind dependent typing's amazing advantage over alternative approaches in several important areas. Here, we have implemented complete syntax, typing rules, and evaluation semantics for simply-typed lambda calculus without even needing to define a syntactic substitution operation. We did it all without a single line of proof, and our implementation is manifestly executable. In a later chapter, we will meet other, more common approaches to language formalization. Such approaches often state and prove explicit theorems about type safety of languages. In the above example, we got type safety, termination, and other meta-theorems for free, by reduction to CIC, which we know has those properties. *)
321 353
322 354
323 (** * Recursive Type Definitions *) 355 (** * Recursive Type Definitions *)
324 356
325 (** There is another style of datatype definition that leads to much simpler definitions of the [get] and [hget] definitions above. Because Coq supports "type-level computation," we can redo our inductive definitions as %\textit{%#<i>#recursive#</i>#%}% definitions. *) 357 (** There is another style of datatype definition that leads to much simpler definitions of the [get] and [hget] definitions above. Because Coq supports "type-level computation," we can redo our inductive definitions as %\textit{%#<i>#recursive#</i>#%}% definitions. *)
358
359 (* EX: Come up with an alternate [ilist] definition that makes it easier to write [get]. *)
326 360
327 Section filist. 361 Section filist.
328 Variable A : Set. 362 Variable A : Set.
329 363
364 (* begin thide *)
330 Fixpoint filist (n : nat) : Set := 365 Fixpoint filist (n : nat) : Set :=
331 match n with 366 match n with
332 | O => unit 367 | O => unit
333 | S n' => A * filist n' 368 | S n' => A * filist n'
334 end%type. 369 end%type.
352 | Some idx' => fget n' (snd ls) idx' 387 | Some idx' => fget n' (snd ls) idx'
353 end 388 end
354 end. 389 end.
355 390
356 (** Our new [get] implementation needs only one dependent [match], which just copies the stated return type of the function. Our choices of data structure implementations lead to just the right typing behavior for this new definition to work out. *) 391 (** Our new [get] implementation needs only one dependent [match], which just copies the stated return type of the function. Our choices of data structure implementations lead to just the right typing behavior for this new definition to work out. *)
392 (* end thide *)
357 End filist. 393 End filist.
358 394
359 (** Heterogeneous lists are a little trickier to define with recursion, but we then reap similar benefits in simplicity of use. *) 395 (** Heterogeneous lists are a little trickier to define with recursion, but we then reap similar benefits in simplicity of use. *)
396
397 (* EX: Come up with an alternate [hlist] definition that makes it easier to write [hget]. *)
360 398
361 Section fhlist. 399 Section fhlist.
362 Variable A : Type. 400 Variable A : Type.
363 Variable B : A -> Type. 401 Variable B : A -> Type.
364 402
403 (* begin thide *)
365 Fixpoint fhlist (ls : list A) : Type := 404 Fixpoint fhlist (ls : list A) : Type :=
366 match ls with 405 match ls with
367 | nil => unit 406 | nil => unit
368 | x :: ls' => B x * fhlist ls' 407 | x :: ls' => B x * fhlist ls'
369 end%type. 408 end%type.
415 454
416 Inductive eq (A : Type) (x : A) : A -> Prop := refl_equal : x = x 455 Inductive eq (A : Type) (x : A) : A -> Prop := refl_equal : x = x
417 ]] 456 ]]
418 457
419 In a proposition [x = y], we see that [x] is a parameter and [y] is a regular argument. The type of the constructor [refl_equal] shows that [y] can only ever be instantiated to [x]. Thus, within a pattern-match with [refl_equal], occurrences of [y] can be replaced with occurrences of [x] for typing purposes. All examples of similar dependent pattern matching that we have seen before require explicit annotations, but Coq implements a special case of annotation inference for matches on equality proofs. *) 458 In a proposition [x = y], we see that [x] is a parameter and [y] is a regular argument. The type of the constructor [refl_equal] shows that [y] can only ever be instantiated to [x]. Thus, within a pattern-match with [refl_equal], occurrences of [y] can be replaced with occurrences of [x] for typing purposes. All examples of similar dependent pattern matching that we have seen before require explicit annotations, but Coq implements a special case of annotation inference for matches on equality proofs. *)
459 (* end thide *)
420 End fhlist. 460 End fhlist.
421 461
422 Implicit Arguments fhget [A B elm ls]. 462 Implicit Arguments fhget [A B elm ls].
423 463
424 464
461 end. 501 end.
462 502
463 (** Now we might like to prove that [inc] does not decrease a tree's [sum]. *) 503 (** Now we might like to prove that [inc] does not decrease a tree's [sum]. *)
464 504
465 Theorem sum_inc : forall t, sum (inc t) >= sum t. 505 Theorem sum_inc : forall t, sum (inc t) >= sum t.
506 (* begin thide *)
466 induction t; crush. 507 induction t; crush.
467 (** [[ 508 (** [[
468 509
469 n : nat 510 n : nat
470 i : ilist (tree nat) n 511 i : ilist (tree nat) n
569 Hint Resolve sum_inc'. 610 Hint Resolve sum_inc'.
570 611
571 induction t; crush. 612 induction t; crush.
572 Qed. 613 Qed.
573 614
615 (* end thide *)
616
574 (** Even if Coq would generate complete induction principles automatically for nested inductive definitions like the one we started with, there would still be advantages to using this style of reflexive encoding. We see one of those advantages in the definition of [inc], where we did not need to use any kind of auxiliary function. In general, reflexive encodings often admit direct implementations of operations that would require recursion if performed with more traditional inductive data structures. *) 617 (** Even if Coq would generate complete induction principles automatically for nested inductive definitions like the one we started with, there would still be advantages to using this style of reflexive encoding. We see one of those advantages in the definition of [inc], where we did not need to use any kind of auxiliary function. In general, reflexive encodings often admit direct implementations of operations that would require recursion if performed with more traditional inductive data structures. *)
575 618
576 (** ** Another Interpreter Example *) 619 (** ** Another Interpreter Example *)
577 620
578 (** We develop another example of variable-arity constructors, in the form of optimization of a small expression language with a construct like Scheme's %\texttt{%#<tt>#cond#</tt>#%}%. Each of our conditional expressions takes a list of pairs of boolean tests and bodies. The value of the conditional comes from the body of the first test in the list to evaluate to [true]. To simplify the interpreter we will write, we force each conditional to include a final, default case. *) 621 (** We develop another example of variable-arity constructors, in the form of optimization of a small expression language with a construct like Scheme's %\texttt{%#<tt>#cond#</tt>#%}%. Each of our conditional expressions takes a list of pairs of boolean tests and bodies. The value of the conditional comes from the body of the first test in the list to evaluate to [true]. To simplify the interpreter we will write, we force each conditional to include a final, default case. *)
583 | NConst : nat -> exp' Nat 626 | NConst : nat -> exp' Nat
584 | Plus : exp' Nat -> exp' Nat -> exp' Nat 627 | Plus : exp' Nat -> exp' Nat -> exp' Nat
585 | Eq : exp' Nat -> exp' Nat -> exp' Bool 628 | Eq : exp' Nat -> exp' Nat -> exp' Bool
586 629
587 | BConst : bool -> exp' Bool 630 | BConst : bool -> exp' Bool
631 (* begin thide *)
588 | Cond : forall n t, (findex n -> exp' Bool) 632 | Cond : forall n t, (findex n -> exp' Bool)
589 -> (findex n -> exp' t) -> exp' t -> exp' t. 633 -> (findex n -> exp' t) -> exp' t -> exp' t.
634 (* end thide *)
590 635
591 (** A [Cond] is parameterized by a natural [n], which tells us how many cases this conditional has. The test expressions are represented with a function of type [findex n -> exp' Bool], and the bodies are represented with a function of type [findex n -> exp' t], where [t] is the overall type. The final [exp' t] argument is the default case. 636 (** A [Cond] is parameterized by a natural [n], which tells us how many cases this conditional has. The test expressions are represented with a function of type [findex n -> exp' Bool], and the bodies are represented with a function of type [findex n -> exp' t], where [t] is the overall type. The final [exp' t] argument is the default case.
592 637
593 We start implementing our interpreter with a standard type denotation function. *) 638 We start implementing our interpreter with a standard type denotation function. *)
594 639
598 | Bool => bool 643 | Bool => bool
599 end. 644 end.
600 645
601 (** To implement the expression interpreter, it is useful to have the following function that implements the functionality of [Cond] without involving any syntax. *) 646 (** To implement the expression interpreter, it is useful to have the following function that implements the functionality of [Cond] without involving any syntax. *)
602 647
648 (* begin thide *)
603 Section cond. 649 Section cond.
604 Variable A : Set. 650 Variable A : Set.
605 Variable default : A. 651 Variable default : A.
606 652
607 Fixpoint cond (n : nat) : (findex n -> bool) -> (findex n -> A) -> A := 653 Fixpoint cond (n : nat) : (findex n -> bool) -> (findex n -> A) -> A :=
615 (fun idx => bodies (Some idx)) 661 (fun idx => bodies (Some idx))
616 end. 662 end.
617 End cond. 663 End cond.
618 664
619 Implicit Arguments cond [A n]. 665 Implicit Arguments cond [A n].
666 (* end thide *)
620 667
621 (** Now the expression interpreter is straightforward to write. *) 668 (** Now the expression interpreter is straightforward to write. *)
622 669
623 Fixpoint exp'Denote t (e : exp' t) {struct e} : type'Denote t := 670 Fixpoint exp'Denote t (e : exp' t) {struct e} : type'Denote t :=
624 match e in exp' t return type'Denote t with 671 match e in exp' t return type'Denote t with
630 if eq_nat_dec (exp'Denote e1) (exp'Denote e2) then true else false 677 if eq_nat_dec (exp'Denote e1) (exp'Denote e2) then true else false
631 678
632 | BConst b => 679 | BConst b =>
633 b 680 b
634 | Cond _ _ tests bodies default => 681 | Cond _ _ tests bodies default =>
682 (* begin thide *)
635 cond 683 cond
636 (exp'Denote default) 684 (exp'Denote default)
637 (fun idx => exp'Denote (tests idx)) 685 (fun idx => exp'Denote (tests idx))
638 (fun idx => exp'Denote (bodies idx)) 686 (fun idx => exp'Denote (bodies idx))
687 (* end thide *)
639 end. 688 end.
640 689
641 (** We will implement a constant-folding function that optimizes conditionals, removing cases with known-[false] tests and cases that come after known-[true] tests. A function [cfoldCond] implements the heart of this logic. The convoy pattern is used again near the end of the implementation. *) 690 (** We will implement a constant-folding function that optimizes conditionals, removing cases with known-[false] tests and cases that come after known-[true] tests. A function [cfoldCond] implements the heart of this logic. The convoy pattern is used again near the end of the implementation. *)
642 691
692 (* begin thide *)
643 Section cfoldCond. 693 Section cfoldCond.
644 Variable t : type'. 694 Variable t : type'.
645 Variable default : exp' t. 695 Variable default : exp' t.
646 696
647 Fixpoint cfoldCond (n : nat) 697 Fixpoint cfoldCond (n : nat)
681 end 731 end
682 end. 732 end.
683 End cfoldCond. 733 End cfoldCond.
684 734
685 Implicit Arguments cfoldCond [t n]. 735 Implicit Arguments cfoldCond [t n].
736 (* end thide *)
686 737
687 (** Like for the interpreters, most of the action was in this helper function, and [cfold] itself is easy to write. *) 738 (** Like for the interpreters, most of the action was in this helper function, and [cfold] itself is easy to write. *)
688 739
689 Fixpoint cfold t (e : exp' t) {struct e} : exp' t := 740 Fixpoint cfold t (e : exp' t) {struct e} : exp' t :=
690 match e in exp' t return exp' t with 741 match e in exp' t return exp' t with
704 | _, _ => Eq e1' e2' 755 | _, _ => Eq e1' e2'
705 end 756 end
706 757
707 | BConst b => BConst b 758 | BConst b => BConst b
708 | Cond _ _ tests bodies default => 759 | Cond _ _ tests bodies default =>
760 (* begin thide *)
709 cfoldCond 761 cfoldCond
710 (cfold default) 762 (cfold default)
711 (fun idx => cfold (tests idx)) 763 (fun idx => cfold (tests idx))
712 (fun idx => cfold (bodies idx)) 764 (fun idx => cfold (bodies idx))
765 (* end thide *)
713 end. 766 end.
714 767
768 (* begin thide *)
715 (** To prove our final correctness theorem, it is useful to know that [cfoldCond] preserves expression meanings. This lemma formalizes that property. The proof is a standard mostly-automated one, with the only wrinkle being a guided instantation of the quantifiers in the induction hypothesis. *) 769 (** To prove our final correctness theorem, it is useful to know that [cfoldCond] preserves expression meanings. This lemma formalizes that property. The proof is a standard mostly-automated one, with the only wrinkle being a guided instantation of the quantifiers in the induction hypothesis. *)
716 770
717 Lemma cfoldCond_correct : forall t (default : exp' t) 771 Lemma cfoldCond_correct : forall t (default : exp' t)
718 n (tests : findex n -> exp' Bool) (bodies : findex n -> exp' t), 772 n (tests : findex n -> exp' Bool) (bodies : findex n -> exp' t),
719 exp'Denote (cfoldCond default tests bodies) 773 exp'Denote (cfoldCond default tests bodies)
749 | [ |- context[if ?E then _ else _] ] => destruct E 803 | [ |- context[if ?E then _ else _] ] => destruct E
750 end; crush. 804 end; crush.
751 Qed. 805 Qed.
752 806
753 (** Now the final theorem is easy to prove. We add our two lemmas as hints and perform standard automation with pattern-matching of subterms to destruct. *) 807 (** Now the final theorem is easy to prove. We add our two lemmas as hints and perform standard automation with pattern-matching of subterms to destruct. *)
808 (* end thide *)
754 809
755 Theorem cfold_correct : forall t (e : exp' t), 810 Theorem cfold_correct : forall t (e : exp' t),
756 exp'Denote (cfold e) = exp'Denote e. 811 exp'Denote (cfold e) = exp'Denote e.
812 (* begin thide *)
757 Hint Rewrite cfoldCond_correct : cpdt. 813 Hint Rewrite cfoldCond_correct : cpdt.
758 Hint Resolve cond_ext. 814 Hint Resolve cond_ext.
759 815
760 induction e; crush; 816 induction e; crush;
761 repeat (match goal with 817 repeat (match goal with
762 | [ |- context[cfold ?E] ] => dep_destruct (cfold E) 818 | [ |- context[cfold ?E] ] => dep_destruct (cfold E)
763 end; crush). 819 end; crush).
764 Qed. 820 Qed.
821 (* end thide *)