Mercurial > cpdt > repo
comparison src/InductiveTypes.v @ 279:fabbc71abd80
Incorporate PC's comments on InductiveTypes
author | Adam Chlipala <adam@chlipala.net> |
---|---|
date | Fri, 01 Oct 2010 14:19:20 -0400 |
parents | c4b1c0de7af9 |
children | 4146889930c5 |
comparison
equal
deleted
inserted
replaced
278:e7ed2fddd29a | 279:fabbc71abd80 |
---|---|
18 | 18 |
19 (** %\part{Basic Programming and Proving} | 19 (** %\part{Basic Programming and Proving} |
20 | 20 |
21 \chapter{Introducing Inductive Types}% *) | 21 \chapter{Introducing Inductive Types}% *) |
22 | 22 |
23 (** In a sense, CIC is built from just two relatively straightforward features: function types and inductive types. From this modest foundation, we can prove effectively all of the theorems of math and carry out effectively all program verifications, with enough effort expended. This chapter introduces induction and recursion for functional programming in Coq. *) | 23 (** In a sense, CIC is built from just two relatively straightforward features: function types and inductive types. From this modest foundation, we can prove effectively all of the theorems of math and carry out effectively all program verifications, with enough effort expended. This chapter introduces induction and recursion for functional programming in Coq. Most of our examples reproduce functionality from the Coq standard library, and we have tried to copy the standard library's choices of identifiers, where possible, so many of the definitions here are already available in the default Coq environment. *) |
24 | 24 |
25 | 25 |
26 (** * Enumerations *) | 26 (** * Enumerations *) |
27 | 27 |
28 (** Coq inductive types generalize the algebraic datatypes found in Haskell and ML. Confusingly enough, inductive types also generalize generalized algebraic datatypes (GADTs), by adding the possibility for type dependency. Even so, it is worth backing up from the examples of the last chapter and going over basic, algebraic datatype uses of inductive datatypes, because the chance to prove things about the values of these types adds new wrinkles beyond usual practice in Haskell and ML. | 28 (** Coq inductive types generalize the algebraic datatypes found in Haskell and ML. Confusingly enough, inductive types also generalize generalized algebraic datatypes (GADTs), by adding the possibility for type dependency. Even so, it is worth backing up from the examples of the last chapter and going over basic, algebraic datatype uses of inductive datatypes, because the chance to prove things about the values of these types adds new wrinkles beyond usual practice in Haskell and ML. |
116 | true | 116 | true |
117 | false. | 117 | false. |
118 | 118 |
119 (** We can use less vacuous pattern matching to define boolean negation. *) | 119 (** We can use less vacuous pattern matching to define boolean negation. *) |
120 | 120 |
121 Definition not (b : bool) : bool := | 121 Definition negb (b : bool) : bool := |
122 match b with | 122 match b with |
123 | true => false | 123 | true => false |
124 | false => true | 124 | false => true |
125 end. | 125 end. |
126 | 126 |
127 (** An alternative definition desugars to the above: *) | 127 (** An alternative definition desugars to the above: *) |
128 | 128 |
129 Definition not' (b : bool) : bool := | 129 Definition negb' (b : bool) : bool := |
130 if b then false else true. | 130 if b then false else true. |
131 | 131 |
132 (** We might want to prove that [not] is its own inverse operation. *) | 132 (** We might want to prove that [negb] is its own inverse operation. *) |
133 | 133 |
134 Theorem not_inverse : forall b : bool, not (not b) = b. | 134 Theorem negb_inverse : forall b : bool, negb (negb b) = b. |
135 (* begin thide *) | 135 (* begin thide *) |
136 destruct b. | 136 destruct b. |
137 | 137 |
138 (** After we case-analyze on [b], we are left with one subgoal for each constructor of [bool]. | 138 (** After we case-analyze on [b], we are left with one subgoal for each constructor of [bool]. |
139 | 139 |
140 [[ | 140 [[ |
141 2 subgoals | 141 2 subgoals |
142 | 142 |
143 ============================ | 143 ============================ |
144 not (not true) = true | 144 negb (negb true) = true |
145 ]] | 145 ]] |
146 | 146 |
147 [[ | 147 [[ |
148 subgoal 2 is: | 148 subgoal 2 is: |
149 not (not false) = false | 149 negb (negb false) = false |
150 | 150 |
151 ]] | 151 ]] |
152 | 152 |
153 The first subgoal follows by Coq's rules of computation, so we can dispatch it easily: *) | 153 The first subgoal follows by Coq's rules of computation, so we can dispatch it easily: *) |
154 | 154 |
161 Qed. | 161 Qed. |
162 (* end thide *) | 162 (* end thide *) |
163 | 163 |
164 (** Another theorem about booleans illustrates another useful tactic. *) | 164 (** Another theorem about booleans illustrates another useful tactic. *) |
165 | 165 |
166 Theorem not_ineq : forall b : bool, not b <> b. | 166 Theorem negb_ineq : forall b : bool, negb b <> b. |
167 (* begin thide *) | 167 (* begin thide *) |
168 destruct b; discriminate. | 168 destruct b; discriminate. |
169 Qed. | 169 Qed. |
170 (* end thide *) | 170 (* end thide *) |
171 | 171 |
934 | Cons tr rest => conj (nat_tree_ind' tr) (list_nat_tree_ind rest) | 934 | Cons tr rest => conj (nat_tree_ind' tr) (list_nat_tree_ind rest) |
935 end. | 935 end. |
936 | 936 |
937 ]] | 937 ]] |
938 | 938 |
939 Coq rejects this definition, saying "Recursive call to nat_tree_ind' has principal argument equal to "tr" instead of rest." The term "nested inductive type" hints at the solution to the problem. Just like true mutually-inductive types require mutually-recursive induction principles, nested types require nested recursion. *) | 939 Coq rejects this definition, saying "Recursive call to nat_tree_ind' has principal argument equal to "tr" instead of rest." There is no deep theoretical reason why this program should be rejected; Coq applies incomplete termination-checking heuristics, and it is necessary to learn a few of the most important rules. The term "nested inductive type" hints at the solution to this particular problem. Just like true mutually-inductive types require mutually-recursive induction principles, nested types require nested recursion. *) |
940 | 940 |
941 Fixpoint nat_tree_ind' (tr : nat_tree) : P tr := | 941 Fixpoint nat_tree_ind' (tr : nat_tree) : P tr := |
942 match tr with | 942 match tr with |
943 | NLeaf' => NLeaf'_case | 943 | NLeaf' => NLeaf'_case |
944 | NNode' n ls => NNode'_case n ls | 944 | NNode' n ls => NNode'_case n ls |
947 | Nil => I | 947 | Nil => I |
948 | Cons tr rest => conj (nat_tree_ind' tr) (list_nat_tree_ind rest) | 948 | Cons tr rest => conj (nat_tree_ind' tr) (list_nat_tree_ind rest) |
949 end) ls) | 949 end) ls) |
950 end. | 950 end. |
951 | 951 |
952 (** We include an anonymous [fix] version of [list_nat_tree_ind] that is literally %\textit{%#<i>#nested#</i>#%}% inside the definition of the recursive function corresponding to the inductive definition that had the nested use of [list]. *) | 952 (** We include an anonymous [fix] version of [list_nat_tree_ind] that is literally %\textit{%#<i>#nested#</i>#%}% inside the definition of the recursive function corresponding to the inductive definition that had the nested use of [list]. *) |
953 | 953 |
954 End nat_tree_ind'. | 954 End nat_tree_ind'. |
955 | 955 |
956 (** We can try our induction principle out by defining some recursive functions on [nat_tree]s and proving a theorem about them. First, we define some helper functions that operate on lists. *) | 956 (** We can try our induction principle out by defining some recursive functions on [nat_tree]s and proving a theorem about them. First, we define some helper functions that operate on lists. *) |
957 | 957 |