comparison src/MoreDep.v @ 380:31fa03bc0f18

Get it to build with Coq 8.4
author Adam Chlipala <adam@chlipala.net>
date Thu, 29 Mar 2012 18:10:52 -0400
parents d1276004eec9
children b911d0df5eee
comparison
equal deleted inserted replaced
379:e23d41ae63be 380:31fa03bc0f18
556 A quick word of encouragement: After writing this code, even I do not understand the precise details of how balancing works! I consulted Chris Okasaki's paper %``%#"#Red-Black Trees in a Functional Setting#"#%''~\cite{Okasaki}% and transcribed the code to use dependent types. Luckily, the details are not so important here; types alone will tell us that insertion preserves balanced-ness, and we will prove that insertion produces trees containing the right keys.*) 556 A quick word of encouragement: After writing this code, even I do not understand the precise details of how balancing works! I consulted Chris Okasaki's paper %``%#"#Red-Black Trees in a Functional Setting#"#%''~\cite{Okasaki}% and transcribed the code to use dependent types. Luckily, the details are not so important here; types alone will tell us that insertion preserves balanced-ness, and we will prove that insertion produces trees containing the right keys.*)
557 557
558 Definition balance1 n (a : rtree n) (data : nat) c2 := 558 Definition balance1 n (a : rtree n) (data : nat) c2 :=
559 match a in rtree n return rbtree c2 n 559 match a in rtree n return rbtree c2 n
560 -> { c : color & rbtree c (S n) } with 560 -> { c : color & rbtree c (S n) } with
561 | RedNode' _ _ _ t1 y t2 => 561 | RedNode' _ c0 _ t1 y t2 =>
562 match t1 in rbtree c n return rbtree _ n -> rbtree c2 n 562 match t1 in rbtree c n return rbtree c0 n -> rbtree c2 n
563 -> { c : color & rbtree c (S n) } with 563 -> { c : color & rbtree c (S n) } with
564 | RedNode _ a x b => fun c d => 564 | RedNode _ a x b => fun c d =>
565 {<RedNode (BlackNode a x b) y (BlackNode c data d)>} 565 {<RedNode (BlackNode a x b) y (BlackNode c data d)>}
566 | t1' => fun t2 => 566 | t1' => fun t2 =>
567 match t2 in rbtree c n return rbtree _ n -> rbtree c2 n 567 match t2 in rbtree c n return rbtree Black n -> rbtree c2 n
568 -> { c : color & rbtree c (S n) } with 568 -> { c : color & rbtree c (S n) } with
569 | RedNode _ b x c => fun a d => 569 | RedNode _ b x c => fun a d =>
570 {<RedNode (BlackNode a y b) x (BlackNode c data d)>} 570 {<RedNode (BlackNode a y b) x (BlackNode c data d)>}
571 | b => fun a t => {<BlackNode (RedNode a y b) data t>} 571 | b => fun a t => {<BlackNode (RedNode a y b) data t>}
572 end t1' 572 end t1'
579 579
580 Here is the symmetric function [balance2], for cases where the possibly invalid tree appears on the right rather than on the left. *) 580 Here is the symmetric function [balance2], for cases where the possibly invalid tree appears on the right rather than on the left. *)
581 581
582 Definition balance2 n (a : rtree n) (data : nat) c2 := 582 Definition balance2 n (a : rtree n) (data : nat) c2 :=
583 match a in rtree n return rbtree c2 n -> { c : color & rbtree c (S n) } with 583 match a in rtree n return rbtree c2 n -> { c : color & rbtree c (S n) } with
584 | RedNode' _ _ _ t1 z t2 => 584 | RedNode' _ c0 _ t1 z t2 =>
585 match t1 in rbtree c n return rbtree _ n -> rbtree c2 n 585 match t1 in rbtree c n return rbtree c0 n -> rbtree c2 n
586 -> { c : color & rbtree c (S n) } with 586 -> { c : color & rbtree c (S n) } with
587 | RedNode _ b y c => fun d a => 587 | RedNode _ b y c => fun d a =>
588 {<RedNode (BlackNode a data b) y (BlackNode c z d)>} 588 {<RedNode (BlackNode a data b) y (BlackNode c z d)>}
589 | t1' => fun t2 => 589 | t1' => fun t2 =>
590 match t2 in rbtree c n return rbtree _ n -> rbtree c2 n 590 match t2 in rbtree c n return rbtree Black n -> rbtree c2 n
591 -> { c : color & rbtree c (S n) } with 591 -> { c : color & rbtree c (S n) } with
592 | RedNode _ c z' d => fun b a => 592 | RedNode _ c z' d => fun b a =>
593 {<RedNode (BlackNode a data b) z (BlackNode c z' d)>} 593 {<RedNode (BlackNode a data b) z (BlackNode c z' d)>}
594 | b => fun a t => {<BlackNode t data (RedNode a z b)>} 594 | b => fun a t => {<BlackNode t data (RedNode a z b)>}
595 end t1' 595 end t1'
1130 refine (fix F (l : nat) : {exists l', S l' <= l 1130 refine (fix F (l : nat) : {exists l', S l' <= l
1131 /\ P (substring n (S l') s) /\ P' (substring (n + S l') (length s - (n + S l')) s)} 1131 /\ P (substring n (S l') s) /\ P' (substring (n + S l') (length s - (n + S l')) s)}
1132 + {forall l', S l' <= l 1132 + {forall l', S l' <= l
1133 -> ~ P (substring n (S l') s) 1133 -> ~ P (substring n (S l') s)
1134 \/ ~ P' (substring (n + S l') (length s - (n + S l')) s)} := 1134 \/ ~ P' (substring (n + S l') (length s - (n + S l')) s)} :=
1135 match l with 1135 match l return {exists l', S l' <= l
1136 /\ P (substring n (S l') s) /\ P' (substring (n + S l') (length s - (n + S l')) s)}
1137 + {forall l', S l' <= l
1138 -> ~ P (substring n (S l') s)
1139 \/ ~ P' (substring (n + S l') (length s - (n + S l')) s)} with
1136 | O => _ 1140 | O => _
1137 | S l' => 1141 | S l' =>
1138 (P_dec (substring n (S l') s) && P'_dec (n' := n + S l') _) 1142 (P_dec (substring n (S l') s) && P'_dec (n' := n + S l') _)
1139 || F l' 1143 || F l'
1140 end); clear F; crush; eauto 7; 1144 end); clear F; crush; eauto 7;
1184 | [ H1 : _ < _ - _, H2 : forall l' : nat, _ <= _ - _ -> _ |- _ ] => 1188 | [ H1 : _ < _ - _, H2 : forall l' : nat, _ <= _ - _ -> _ |- _ ] =>
1185 generalize (H2 _ (lt_le_S _ _ H1)); tauto 1189 generalize (H2 _ (lt_le_S _ _ H1)); tauto
1186 end. 1190 end.
1187 Defined. 1191 Defined.
1188 1192
1189 (** Finally, we have [dec_star]. It has a straightforward implementation. We introduce a spurious match on [s] so that [simpl] will know to reduce calls to [dec_star]. The heuristic that [simpl] uses is only to unfold identifier definitions when doing so would simplify some [match] expression. *) 1193 (** Finally, we have [dec_star], defined by straightforward reduction from [dec_star']. *)
1190 1194
1191 Definition dec_star : {star P s} + {~ star P s}. 1195 Definition dec_star : {star P s} + {~ star P s}.
1192 refine (match s return _ with 1196 refine (Reduce (dec_star' (n := length s) 0 _)); crush.
1193 | "" => Reduce (dec_star' (n := length s) 0 _)
1194 | _ => Reduce (dec_star' (n := length s) 0 _)
1195 end); crush.
1196 Defined. 1197 Defined.
1197 End dec_star. 1198 End dec_star.
1198 1199
1199 (* begin hide *) 1200 (* begin hide *)
1200 Lemma app_cong : forall x1 y1 x2 y2, 1201 Lemma app_cong : forall x1 y1 x2 y2,
1224 1225
1225 (** It is interesting to pause briefly to consider alternate implementations of [matches]. Dependent types give us much latitude in how specific correctness properties may be encoded with types. For instance, we could have made [regexp] a non-indexed inductive type, along the lines of what is possible in traditional ML and Haskell. We could then have implemented a recursive function to map [regexp]s to their intended meanings, much as we have done with types and programs in other examples. That style is compatible with the [refine]-based approach that we have used here, and it might be an interesting exercise to redo the code from this subsection in that alternate style or some further encoding of the reader's choice. The main advantage of indexed inductive types is that they generally lead to the smallest amount of code. *) 1226 (** It is interesting to pause briefly to consider alternate implementations of [matches]. Dependent types give us much latitude in how specific correctness properties may be encoded with types. For instance, we could have made [regexp] a non-indexed inductive type, along the lines of what is possible in traditional ML and Haskell. We could then have implemented a recursive function to map [regexp]s to their intended meanings, much as we have done with types and programs in other examples. That style is compatible with the [refine]-based approach that we have used here, and it might be an interesting exercise to redo the code from this subsection in that alternate style or some further encoding of the reader's choice. The main advantage of indexed inductive types is that they generally lead to the smallest amount of code. *)
1226 1227
1227 (* begin hide *) 1228 (* begin hide *)
1228 Example hi := Concat (Char "h"%char) (Char "i"%char). 1229 Example hi := Concat (Char "h"%char) (Char "i"%char).
1229 Eval simpl in matches hi "hi". 1230 Eval hnf in matches hi "hi".
1230 Eval simpl in matches hi "bye". 1231 Eval hnf in matches hi "bye".
1231 1232
1232 Example a_b := Or (Char "a"%char) (Char "b"%char). 1233 Example a_b := Or (Char "a"%char) (Char "b"%char).
1233 Eval simpl in matches a_b "". 1234 Eval hnf in matches a_b "".
1234 Eval simpl in matches a_b "a". 1235 Eval hnf in matches a_b "a".
1235 Eval simpl in matches a_b "aa". 1236 Eval hnf in matches a_b "aa".
1236 Eval simpl in matches a_b "b". 1237 Eval hnf in matches a_b "b".
1237 (* end hide *) 1238 (* end hide *)
1238 1239
1239 (** Many regular expression matching problems are easy to test. The reader may run each of the following queries to verify that it gives the correct answer. *) 1240 (** Many regular expression matching problems are easy to test. The reader may run each of the following queries to verify that it gives the correct answer. We use evaluation strategy %\index{tactics!hnf}%[hnf] to reduce each term to %\index{head-normal form}\emph{%#<i>#head-normal form#</i>#%}%, where the datatype constructor used to build its value is known. *)
1240 1241
1241 Example a_star := Star (Char "a"%char). 1242 Example a_star := Star (Char "a"%char).
1242 Eval simpl in matches a_star "". 1243 Eval hnf in matches a_star "".
1243 Eval simpl in matches a_star "a". 1244 Eval hnf in matches a_star "a".
1244 Eval simpl in matches a_star "b". 1245 Eval hnf in matches a_star "b".
1245 Eval simpl in matches a_star "aa". 1246 Eval hnf in matches a_star "aa".
1246 1247
1247 (** Evaluation inside Coq does not scale very well, so it is easy to build other tests that run for hours or more. Such cases are better suited to execution with the extracted OCaml code. *) 1248 (** Evaluation inside Coq does not scale very well, so it is easy to build other tests that run for hours or more. Such cases are better suited to execution with the extracted OCaml code. *)