Mercurial > cpdt > repo
comparison src/Reflection.v @ 461:b6c47e6d43dc
Proofreading pass through Chapter 15
author | Adam Chlipala <adam@chlipala.net> |
---|---|
date | Wed, 29 Aug 2012 15:36:06 -0400 |
parents | 0650420c127b |
children | 40a9a36844d6 |
comparison
equal
deleted
inserted
replaced
460:38549f152568 | 461:b6c47e6d43dc |
---|---|
83 | 1 => No | 83 | 1 => No |
84 | S (S n') => Reduce (F n') | 84 | S (S n') => Reduce (F n') |
85 end); auto. | 85 end); auto. |
86 Defined. | 86 Defined. |
87 | 87 |
88 (** The function [check_even] may be viewed as a _verified decision procedure_, because its type guarantees that it never returns [Yes] for inputs that are not even. | 88 (** The function [check_even] may be viewed as a _verified decision procedure_, because its type guarantees that it never returns %\coqdocnotation{%#<tt>#Yes#</tt>#%}% for inputs that are not even. |
89 | 89 |
90 Now we can use dependent pattern-matching to write a function that performs a surprising feat. When given a [partial P], this function [partialOut] returns a proof of [P] if the [partial] value contains a proof, and it returns a (useless) proof of [True] otherwise. From the standpoint of ML and Haskell programming, it seems impossible to write such a type, but it is trivial with a [return] annotation. *) | 90 Now we can use dependent pattern-matching to write a function that performs a surprising feat. When given a [partial P], this function [partialOut] returns a proof of [P] if the [partial] value contains a proof, and it returns a (useless) proof of [True] otherwise. From the standpoint of ML and Haskell programming, it seems impossible to write such a type, but it is trivial with a [return] annotation. *) |
91 | 91 |
92 Definition partialOut (P : Prop) (x : [P]) := | 92 Definition partialOut (P : Prop) (x : [P]) := |
93 match x return (match x with | 93 match x return (match x with |
143 | Yes => isEven 255 | 143 | Yes => isEven 255 |
144 | No => True | 144 | No => True |
145 end" while it is expected to have type "isEven 255" | 145 end" while it is expected to have type "isEven 255" |
146 >> | 146 >> |
147 | 147 |
148 As usual, the type checker performs no reductions to simplify error messages. If we reduced the first term ourselves, we would see that [check_even 255] reduces to a [No], so that the first term is equivalent to [True], which certainly does not unify with [isEven 255]. *) | 148 As usual, the type checker performs no reductions to simplify error messages. If we reduced the first term ourselves, we would see that [check_even 255] reduces to a %\coqdocnotation{%#<tt>#No#</tt>#%}%, so that the first term is equivalent to [True], which certainly does not unify with [isEven 255]. *) |
149 | 149 |
150 Abort. | 150 Abort. |
151 | 151 |
152 (** Our tactic [prove_even_reflective] is reflective because it performs a proof search process (a trivial one, in this case) wholly within Gallina, where the only use of Ltac is to translate a goal into an appropriate use of [check_even]. *) | 152 (** Our tactic [prove_even_reflective] is reflective because it performs a proof search process (a trivial one, in this case) wholly within Gallina, where the only use of Ltac is to translate a goal into an appropriate use of [check_even]. *) |
153 | 153 |
218 let t1 := tautReify P1 in | 218 let t1 := tautReify P1 in |
219 let t2 := tautReify P2 in | 219 let t2 := tautReify P2 in |
220 constr:(TautImp t1 t2) | 220 constr:(TautImp t1 t2) |
221 end. | 221 end. |
222 | 222 |
223 (** With [tautReify] available, it is easy to finish our reflective tactic. We look at the goal formula, reflect it, and apply [tautTrue] to the reflected formula. *) | 223 (** With [tautReify] available, it is easy to finish our reflective tactic. We look at the goal formula, reify it, and apply [tautTrue] to the reified formula. *) |
224 | 224 |
225 Ltac obvious := | 225 Ltac obvious := |
226 match goal with | 226 match goal with |
227 | [ |- ?P ] => | 227 | [ |- ?P ] => |
228 let t := tautReify P in | 228 let t := tautReify P in |
299 | Ident => nil | 299 | Ident => nil |
300 | Var x => x :: nil | 300 | Var x => x :: nil |
301 | Op me1 me2 => flatten me1 ++ flatten me2 | 301 | Op me1 me2 => flatten me1 ++ flatten me2 |
302 end. | 302 end. |
303 | 303 |
304 (** [flatten] has a straightforward correctness proof in terms of our [denote] functions. *) | 304 (** This function has a straightforward correctness proof in terms of our [denote] functions. *) |
305 | 305 |
306 Lemma flatten_correct' : forall ml2 ml1, | 306 Lemma flatten_correct' : forall ml2 ml1, |
307 mldenote ml1 + mldenote ml2 = mldenote (ml1 ++ ml2). | 307 mldenote ml1 + mldenote ml2 = mldenote (ml1 ++ ml2). |
308 induction ml1; crush. | 308 induction ml1; crush. |
309 Qed. | 309 Qed. |
420 | Or f1 f2 => formulaDenote atomics f1 \/ formulaDenote atomics f2 | 420 | Or f1 f2 => formulaDenote atomics f1 \/ formulaDenote atomics f2 |
421 | Imp f1 f2 => formulaDenote atomics f1 --> formulaDenote atomics f2 | 421 | Imp f1 f2 => formulaDenote atomics f1 --> formulaDenote atomics f2 |
422 end. | 422 end. |
423 (* end thide *) | 423 (* end thide *) |
424 | 424 |
425 (** The %\index{Gallina terms!varmap}%[varmap] type family implements maps from [index] values. In this case, we define an assignment as a map from variables to [Prop]s. Our reifier [formulaDenote] works with an assignment, and we use the [varmap_find] function to consult the assignment in the [Atomic] case. The first argument to [varmap_find] is a default value, in case the variable is not found. *) | 425 (** The %\index{Gallina terms!varmap}%[varmap] type family implements maps from [index] values. In this case, we define an assignment as a map from variables to [Prop]s. Our interpretation function [formulaDenote] works with an assignment, and we use the [varmap_find] function to consult the assignment in the [Atomic] case. The first argument to [varmap_find] is a default value, in case the variable is not found. *) |
426 | 426 |
427 Section my_tauto. | 427 Section my_tauto. |
428 Variable atomics : asgn. | 428 Variable atomics : asgn. |
429 | 429 |
430 Definition holds (v : index) := varmap_find False v atomics. | 430 Definition holds (v : index) := varmap_find False v atomics. |
699 | (_, ?xs') => | 699 | (_, ?xs') => |
700 let n := lookup x xs' in | 700 let n := lookup x xs' in |
701 constr:(S n) | 701 constr:(S n) |
702 end. | 702 end. |
703 | 703 |
704 (** The next building block is a procedure for reifying a term, given a list of all allowed variable values. We are free to make this procedure partial, where tactic failure may be triggered upon attempting to reflect a term containing subterms not included in the list of variables. The output type of the term is a copy of [formula] where [index] is replaced by [nat], in the type of the constructor for atomic formulas. *) | 704 (** The next building block is a procedure for reifying a term, given a list of all allowed variable values. We are free to make this procedure partial, where tactic failure may be triggered upon attempting to reify a term containing subterms not included in the list of variables. The type of the output term is a copy of [formula] where [index] is replaced by [nat], in the type of the constructor for atomic formulas. *) |
705 | 705 |
706 Inductive formula' : Set := | 706 Inductive formula' : Set := |
707 | Atomic' : nat -> formula' | 707 | Atomic' : nat -> formula' |
708 | Truth' : formula' | 708 | Truth' : formula' |
709 | Falsehood' : formula' | 709 | Falsehood' : formula' |
866 ]] | 866 ]] |
867 *) | 867 *) |
868 | 868 |
869 Abort. | 869 Abort. |
870 | 870 |
871 (** Our encoding here uses Coq functions to represent binding within the terms we reify, which makes it difficult to implement certain functions over reified terms. An alternative would be to represent variables with numbers. This can be done by writing a slightly smarter reification function that detects variable references by detecting when term arguments are just compositions of [fst] and [snd]; from the order of the compositions we may read off the variable number. We leave the details as an exercise for the reader. *) | 871 (** Our encoding here uses Coq functions to represent binding within the terms we reify, which makes it difficult to implement certain functions over reified terms. An alternative would be to represent variables with numbers. This can be done by writing a slightly smarter reification function that identifies variable references by detecting when term arguments are just compositions of [fst] and [snd]; from the order of the compositions we may read off the variable number. We leave the details as an exercise for the reader. *) |