mirror of
https://github.com/achlipala/frap.git
synced 2024-12-01 00:26:18 +00:00
Finished annotating factorial example in Interpreters
This commit is contained in:
parent
2645e91a23
commit
fe8f0fb918
2 changed files with 46 additions and 8 deletions
4
Frap.v
4
Frap.v
|
@ -43,7 +43,7 @@ Ltac invert0 e := invert e; fail.
|
||||||
Ltac invert1 e := invert0 e || (invert e; []).
|
Ltac invert1 e := invert0 e || (invert e; []).
|
||||||
Ltac invert2 e := invert1 e || (invert e; [|]).
|
Ltac invert2 e := invert1 e || (invert e; [|]).
|
||||||
|
|
||||||
Ltac simplify := simpl in *; intros; try autorewrite with core in *.
|
Ltac simplify := repeat progress (simpl in *; intros; try autorewrite with core in *).
|
||||||
|
|
||||||
Ltac linear_arithmetic := intros;
|
Ltac linear_arithmetic := intros;
|
||||||
repeat match goal with
|
repeat match goal with
|
||||||
|
@ -79,3 +79,5 @@ Global Opaque max min.
|
||||||
Infix "==n" := eq_nat_dec (no associativity, at level 50).
|
Infix "==n" := eq_nat_dec (no associativity, at level 50).
|
||||||
|
|
||||||
Export Frap.Map.
|
Export Frap.Map.
|
||||||
|
|
||||||
|
Ltac maps_equal := Frap.Map.M.maps_equal; simplify.
|
||||||
|
|
|
@ -15,6 +15,9 @@ Inductive arith : Set :=
|
||||||
| Minus (e1 e2 : arith)
|
| Minus (e1 e2 : arith)
|
||||||
| Times (e1 e2 : arith).
|
| Times (e1 e2 : arith).
|
||||||
|
|
||||||
|
Example ex1 := Const 42.
|
||||||
|
Example ex2 := Plus (Var "y") (Times (Var "x") (Const 3)).
|
||||||
|
|
||||||
(* The above definition only explains what programs *look like*.
|
(* The above definition only explains what programs *look like*.
|
||||||
* We also care about what they *mean*.
|
* We also care about what they *mean*.
|
||||||
* The natural meaning of an expression is the number it evaluates to.
|
* The natural meaning of an expression is the number it evaluates to.
|
||||||
|
@ -40,10 +43,29 @@ Fixpoint interp (e : arith) (v : valuation) : nat :=
|
||||||
| Times e1 e2 => interp e1 v * interp e2 v
|
| Times e1 e2 => interp e1 v * interp e2 v
|
||||||
end.
|
end.
|
||||||
|
|
||||||
(* Here's an example valuation. Unfortunately, we can't execute code based on
|
(* Here's an example valuation, using an infix operator for map extension. *)
|
||||||
* finite maps, since, for convenience, they use uncomputable features. *)
|
|
||||||
Definition valuation0 : valuation :=
|
Definition valuation0 : valuation :=
|
||||||
$0 $+ ("x", 17).
|
$0 $+ ("x", 17) $+ ("y", 3).
|
||||||
|
|
||||||
|
(* Unfortunately, we can't execute code based on finite maps, since, for
|
||||||
|
* convenience, they use uncomputable features. The reason is that we need a
|
||||||
|
* comparison function, a hash function, etc., to do computable finite-map
|
||||||
|
* implementation, and such things are impossible to compute automatically for
|
||||||
|
* all types in Coq. However, we can still prove theorems about execution of
|
||||||
|
* finite-map programs, and the [simplify] tactics knows how to reduce the
|
||||||
|
* key constructions. *)
|
||||||
|
Theorem interp_ex1 : interp ex1 valuation0 = 42.
|
||||||
|
Proof.
|
||||||
|
simplify.
|
||||||
|
equality.
|
||||||
|
Qed.
|
||||||
|
|
||||||
|
Theorem interp_ex2 : interp ex2 valuation0 = 54.
|
||||||
|
Proof.
|
||||||
|
unfold valuation0.
|
||||||
|
simplify.
|
||||||
|
equality.
|
||||||
|
Qed.
|
||||||
|
|
||||||
(* Here's the silly transformation we defined last time. *)
|
(* Here's the silly transformation we defined last time. *)
|
||||||
Fixpoint commuter (e : arith) : arith :=
|
Fixpoint commuter (e : arith) : arith :=
|
||||||
|
@ -309,14 +331,19 @@ Fixpoint fact (n : nat) : nat :=
|
||||||
| S n' => n * fact n'
|
| S n' => n * fact n'
|
||||||
end.
|
end.
|
||||||
|
|
||||||
|
(* To prove that [factorial] is correct, the real action is in a lemma, to be
|
||||||
|
* proved by induction, showing that the loop works correctly. So, let's first
|
||||||
|
* assign a name to the loop body alone. *)
|
||||||
Definition factorial_body :=
|
Definition factorial_body :=
|
||||||
"output" <- "output" * "input";
|
"output" <- "output" * "input";
|
||||||
"input" <- "input" - 1.
|
"input" <- "input" - 1.
|
||||||
|
|
||||||
(* Note that here we're careful to put the quantified variable [input] *first*,
|
(* Now for that lemma: self-composition of the body's semantics produces the
|
||||||
|
* expected changes in the valuation.
|
||||||
|
* Note that here we're careful to put the quantified variable [input] *first*,
|
||||||
* because the variables coming after it will need to *change* in the course of
|
* because the variables coming after it will need to *change* in the course of
|
||||||
* the induction. Try switching the order to see what goes wrong if we put
|
* the induction. Try switching the order to see what goes wrong if we put
|
||||||
* [input] later. *)
|
e * [input] later. *)
|
||||||
Lemma factorial_ok' : forall input output v,
|
Lemma factorial_ok' : forall input output v,
|
||||||
v $? "input" = Some input
|
v $? "input" = Some input
|
||||||
-> v $? "output" = Some output
|
-> v $? "output" = Some output
|
||||||
|
@ -325,22 +352,31 @@ Lemma factorial_ok' : forall input output v,
|
||||||
Proof.
|
Proof.
|
||||||
induct input; simplify.
|
induct input; simplify.
|
||||||
|
|
||||||
maps_equal; simplify.
|
maps_equal.
|
||||||
|
(* [maps_equal]: prove that two finite maps are equal by considering all
|
||||||
|
* the relevant cases for mappings of different keys. *)
|
||||||
|
|
||||||
rewrite H0.
|
rewrite H0.
|
||||||
f_equal.
|
f_equal.
|
||||||
linear_arithmetic.
|
linear_arithmetic.
|
||||||
|
|
||||||
trivial.
|
trivial.
|
||||||
|
(* [trivial]: Coq maintains a database of simple proof steps, such as proving
|
||||||
|
* a fact by direct appeal to a matching hypothesis. [trivial] asks to try
|
||||||
|
* all such simple steps. *)
|
||||||
|
|
||||||
rewrite H, H0.
|
rewrite H, H0.
|
||||||
|
(* Note the two arguments to one [rewrite]! *)
|
||||||
rewrite (IHinput (output * S input)).
|
rewrite (IHinput (output * S input)).
|
||||||
maps_equal; simplify.
|
(* Note the careful choice of a quantifier instantiation for the IH! *)
|
||||||
|
maps_equal.
|
||||||
f_equal; ring.
|
f_equal; ring.
|
||||||
simplify; f_equal; linear_arithmetic.
|
simplify; f_equal; linear_arithmetic.
|
||||||
simplify; equality.
|
simplify; equality.
|
||||||
Qed.
|
Qed.
|
||||||
|
|
||||||
|
(* Finally, we have the natural correctness condition for factorial as a whole
|
||||||
|
* program. *)
|
||||||
Theorem factorial_ok : forall v input,
|
Theorem factorial_ok : forall v input,
|
||||||
v $? "input" = Some input
|
v $? "input" = Some input
|
||||||
-> exec factorial v $? "output" = Some (fact input).
|
-> exec factorial v $? "output" = Some (fact input).
|
||||||
|
|
Loading…
Reference in a new issue