Mercurial > cpdt > repo
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 *) |