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