Mercurial > cpdt > repo
diff src/Coinductive.v @ 67:55199444e5e7
Finish Coinductive chapter
author | Adam Chlipala <adamc@hcoop.net> |
---|---|
date | Wed, 01 Oct 2008 09:56:32 -0400 |
parents | 21bb59c56b98 |
children | 943478e5a32d |
line wrap: on
line diff
--- a/src/Coinductive.v Wed Oct 01 09:33:44 2008 -0400 +++ b/src/Coinductive.v Wed Oct 01 09:56:32 2008 -0400 @@ -309,7 +309,7 @@ (** * Simple Modeling of Non-Terminating Programs *) -(** We close the chapter with a quick motivating example for more complex uses of co-inductive types. We will define a co-inductive semantics for a simple assembly language and use that semantics to prove that an optimization function is sound. We start by defining a type of instructions. *) +(** We close the chapter with a quick motivating example for more complex uses of co-inductive types. We will define a co-inductive semantics for a simple assembly language and use that semantics to prove that an optimization function is sound. We start by defining types of registers, program labels, and instructions. *) Inductive reg : Set := R1 | R2. Definition label := nat. @@ -320,8 +320,13 @@ | Halt : reg -> instrs | Jeq : reg -> reg -> label -> instrs -> instrs. +(** [Const] stores a constant in a register; [Add] stores in the first register the sum of the values in the second two; [Halt] ends the program, returning the value of its register argument; and [Jeq] jumps to a label if the values in two registers are equal. Each instruction but [Halt] takes an [instrs], which can be read as "list of instructions," as the normal continuation of control flow. + +We can define a program as a list of lists of instructions, where labels will be interpreted as indexing into such a list. *) + Definition program := list instrs. +(** We define a polymorphic map type for register keys, with its associated operations. *) Section regmap. Variable A : Set. @@ -330,7 +335,7 @@ VR2 : A }. - Definition empty v : regmap := Regmap v v. + Definition empty (v : A) : regmap := Regmap v v. Definition get (rm : regmap) (r : reg) : A := match r with | R1 => VR1 rm @@ -343,6 +348,8 @@ end. End regmap. +(** Now comes the interesting part. We define a co-inductive semantics for programs. The definition itself is not surprising. We could change [CoInductive] to [Inductive] and arrive at a valid semantics that only covers terminating program executions. Using [CoInductive] admits infinite derivations for infinite executions. *) + Section run. Variable prog : program. @@ -366,24 +373,32 @@ -> run rm (Jeq r1 r2 l is) v. End run. +(** We can write a function which tracks known register values to attempt to constant fold a sequence of instructions. We track register values with a [regmap (option nat)], where a mapping to [None] indicates no information, and a mapping to [Some n] indicates that the corresponding register is known to have value [n]. *) + Fixpoint constFold (rm : regmap (option nat)) (is : instrs) {struct is} : instrs := match is with | Const r n is => Const r n (constFold (set rm r (Some n)) is) | Add r r1 r2 is => match get rm r1, get rm r2 with - | Some n1, Some n2 => Const r (n1 + n2) (constFold (set rm r (Some (n1 + n2))) is) + | Some n1, Some n2 => + Const r (n1 + n2) (constFold (set rm r (Some (n1 + n2))) is) | _, _ => Add r r1 r2 (constFold (set rm r None) is) end | Halt _ => is | Jeq r1 r2 l is => Jeq r1 r2 l (constFold rm is) end. +(** We characterize when the two types of register maps we are using agree with each other. *) + Definition regmapCompat (rm : regmap nat) (rm' : regmap (option nat)) := forall r, match get rm' r with | None => True | Some v => get rm r = v end. +(** We prove two lemmas about how register map modifications affect compatibility. A tactic [compat] abstracts the common structure of the two proofs. *) + +(** remove printing * *) Ltac compat := unfold regmapCompat in *; crush; match goal with | [ |- match get _ ?R with Some _ => _ | None => _ end ] => destruct R; crush @@ -401,7 +416,7 @@ destruct r; compat. Qed. -Require Import Arith. +(** Finally, we can prove the main theorem. *) Section constFold_ok. Variable prog : program. @@ -416,10 +431,16 @@ cofix; destruct 1; crush; eauto; repeat match goal with - | [ H : regmapCompat _ _ |- run _ _ (match get ?RM ?R with Some _ => _ | None => _ end) _ ] => + | [ H : regmapCompat _ _ + |- run _ _ (match get ?RM ?R with + | Some _ => _ + | None => _ + end) _ ] => generalize (H R); destruct (get RM R); crush end. Qed. End constFold_ok. +(** If we print the proof term that was generated, we can verify that the proof is structured as a [cofix], with each co-recursive call properly guarded. *) + Print constFold_ok.