
1 | Z ::= X;; |
A weird convention through out all IMP is:
a-: arithb-: boolc-: command
Arithmetic and Boolean Expression
Abstract Syntax
1 | a ::= |
1 | Inductive aexp : Type := |
Evaluation
TODO: is this considered as “denotational semantics”?
1 | Fixpoint aeval (a : aexp) : nat := |
Supposed we have a Fixpoint optimize_0plus (a:aexp) : aexp
1 | Theorem optimize_0plus_sound: ∀a, |
During the proof, many cases of destruct aexp are similar!
Recursive cases such as APlus, AMinus, AMult all require duplicated IH application.
From Coq Intensive:
when wesimplonAPluscase. it’s not “simplified” but give us a pattern matching.
That’s a hint that we need to furthur case analysis bydestruct nas0case or_case.
Coq Automation
Tacticals
“higher-order tactics”.
try T and ; tacticals
if
Tfail,try Tsuccessfully does nothing at all
T;T': performsT'on each subgoal generated byT.
Super blindly but useful: (only leave the “interesting” one.)
1 | induction a; |
. is the atomic; cannot be stepped into…
T; [T1 | T2 | ... | Tn] tacticals
general form or
;T;T'is shorthand for:T; [T' | T' | ... | T'].
repeat tacticals
1 | Theorem In10 : In 10 [1;2;3;4;5;6;7;8;9;10]. |
- stop when it fails
- always succeeds, then loop forever! e.g.
repeat simpl
This does not affect Coq’s logical consistency,
construction process diverges means we have failed to construct a proof, not that we have constructed a wrong one.
Defining New Tactic Notations
Tactic Notation: syntax extension for tactics (good for simple macros)
1 | Tactic Notation "simpl_and_try" tactic(c) := |
Ltac: scripting language for tactics (good for more sophisticated proof engineering)- OCaml tactic scripting API (for wizards)
The omega Tactic
Presburger arithmetic
- arith, equality, ordering, logic connectives
O(doubly expontential)
A Few More Handy Tactics
clear Hsubst x,substrename ... into ...(change auto-generated name that we don’t like…)
the below three are very useful in Coq Automation (w/ try T; T')
assumptioncontradictionconstructor(try toapplyall constructors.
Problem: might have multiple constructors applicable but some fail)
Evaluation as a Relation
Defined as Binary relation on aexp × nat.
Exactly Big Step / Structural Operational Semantics.
More flexible than Fixpoint (computation, or Denotational).
…Since we can operate on Inductive as data I guess?
…and we can also induction on the relation.
…and when things getting more and more “un-computable” (see below).
译注:求值关系不满足对称性,因为它是有方向的。
1 | Inductive aevalR : aexp → nat → Prop := |
Noticed now we now define
inductivein a mixed style:
some arg is before:(named), some are after:(anonymous).
We could do this as well
1 | | E_APlus (e1 e2: aexp) (n1 n2: nat) |
Reserved Notation allow us using the notation during the definition!
1 | Reserved Notation "e '\\' n" (at level 90, left associativity). |
I hated this infix \\ notation…it tries to mimic ⇓ (double down arrow).
e1 \\ n1
e2 \\ n2
-------------------- (E_APlus)
APlus e1 e2 \\ n1+n2
is actually:
e1 ⇓ n1
e2 ⇓ n2
-------------------- (E_APlus)
APlus e1 e2 ⇓ n1+n2
Coq Intensive:
If you have two variables above the line. Think about if you needgeneralize dependent.
Computational vs. Relational Definitions INTERESTING
In some cases, relational definition are much better than computational (a.k.a. functional).
for situations, where thing beingdefined is not easy to express as a function (or not a function at all)
case 1 - safe division
1 | Inductive aexp : Type := |
- functional: how to return
ADiv (ANum 5) (ANum 0)? probably has to beoption(Coq is total!) - relational:
(a1 \\ n1) → (a2 \\ n2) → (n2 > 0) → (mult n2 n3 = n1) → (ADiv a1 a2) \\ n3.- we can add a constraint
(n2 > 0).
- we can add a constraint
case 2 - non-determinism
1 | Inductive aexp : Type := |
- functional: not a deterministic function…
- relational:
E_Any (n : nat) : AAny \\ n… just say it’s the case.
Nonetheless, functional definition is good at:
- by definition deterministic (need proof in relational case)
- take advantage of Coq’s computation engine.
- function can be directly “extracted” from Gallina to OCaml/Haskell
In large Coq developments:
- given both styles
- a lemma stating they coincise (等价)
Expressions with Variables
State (Environment) 环境
A machine state (or just state) represents the current values of all variables at some point in the execution of a program.
1 | Definition state := total_map nat. |
Syntax
1 | Inductive aexp : Type := |
Notations & Coercisons – “meta-programming” and AST quasi-quotation
Quasi-quotation
OCaml PPX & AST quasi-quotation
quasi-quotation enables one to introduce symbols that stand for a linguistic expression in a given instance and are used as that linguistic expression in a different instance.
e.g. in above OCaml example, you wrote %expr 2 + 2 and you get [%expr [%e 2] + [%e 2]].
Coq’s Notation Scope + Coercision == built-in Quasi-quotation
1 | (** Coercision for constructors **) |
Evaluation w/ State (Environment)
Noticed that the st has to be threaded all the way…
1 | Fixpoint aeval (st : state) (a : aexp) : nat := |
Commands (Statement)
1 | c ::= SKIP | x ::= a | c ;; c | TEST b THEN c ELSE c FI | WHILE b DO c END |
we use
TESTto avoid conflicting with theifandIFnotations from the standard library.
1 | Inductive com : Type := |
notation magics:
1 | Bind Scope imp_scope with com. |
Unset Notations
1 | Unset Printing Notations. (** e1 + e2 -> APlus e1 e2 **) |
The Locate command
1 | Locate "&&". |
Evaluating Commands
Noticed that to use quasi-quotation in pattern matching, we need
1 | Open Scope imp_scope. |
An infinite loop (the %imp scope is inferred)
1 | Definition loop : com := |
The fact that
WHILEloops don’t necessarily terminate makes defining an evaluation function tricky…
Evaluation as function (FAIL)
In OCaml/Haskell, we simply recurse, but In Coq
1 | | WHILE b DO c END => if (beval st b) |
Well, if Coq allowed (potentially) non-terminating, the logic would be inconsistent:
1 | Fixpoint loop_false (n : nat) : False := loop_false n. (** False is proved! **) |
Step-Indexed Evaluator (SUCC)
Chapter ImpCEvalFun provide some workarounds to make functional evalution works:
- step-indexed evaluator, i.e. limit the recursion depth. (think about Depth-Limited Search).
- return
optionto tell if it’s a normal or abnormal termination. - use
LETOPT...IN...to reduce the “optional unwrapping” (basicaly Monadic binding>>=!)
- this approach of
let-bindingbecame so popular in ML family.
Evaluation as Relation (SUCC)
Again, we are using some fancy notation st=[c]=>st' to mimic ⇓:
In both PLT and TaPL, we are almost exclusively use Small-Step, but in PLC, Big-Step were used:
beval st b1 = true
st =[ c1 ]=> st'
--------------------------------------- (E_IfTrue)
st =[ TEST b1 THEN c1 ELSE c2 FI ]=> st'
is really:
H; b1 ⇓ true
H; c1 ⇓ H'
---------------------------------- (E_IfTrue)
H; TEST b1 THEN c1 ELSE c2 FI ⇓ H'
1 | Reserved Notation "st '=[' c ']⇒' st'" (at level 40). |
By definition evaluation as relation (in Type level),
we need to construct proofs (terms) to define example.
…noticed that in the definition of relaiton ceval, we actually use the computational aevel, beval..
…noticed that we are using explicit ∀ style rather than constructor argument style (for IDK reason). They are the same!
Determinism of Evaluation
Changing from a computational to a relational definition of evaluation is a good move because it frees us from the artificial requirement that evaluation should be a total function
求值不再必须是全函数
But it also raises a question: Is the second definition of evaluation really a partial function?
这个定义真的是偏函数吗?(这里的重点在于 偏函数 要求 right-unique 即 deterministic)
we can prove:
1 | Theorem ceval_deterministic: ∀c st st1 st2, |
Reasoning About Imp Programs
Case plus2_spec
1 | Theorem plus2_spec : ∀st n st', |
this looks much better as inference rules:
H(x) = n
H; x := x + 2 ⇓ H'
--------------------- (plus2_spec)
H'(x) = n + 2
By inversion on the Big Step eval relation, we can expand one step of ceval
(对 derivation tree 的 expanding 过程其实就是展开我们所需的计算步骤的过程)
st : string -> nat
=================================
(X !-> st X + 2; st) X = st X + 2
In inference rule:
H : string → nat
================================
(x ↦ H(x) + 2); H)(x) = H(x) + 2
Case no_whiles_terminating
1 | Theorem no_whilesR_terminating_fail: |
If we intros st before induction c,
the IH would be for particular st and too specific for E_Seq
(It’s actually okay for TEST since both branch derive from the same st)
1 | IHno_whilesR1 : exists st' : state, st =[ c1 ]=> st' |
So we’d love to
1 | generalize dependent st. |
Additional Exerciese
Stack Compiler
Things that evaluate arithmetic expressions using stack:
- Old HP Calculators
- Forth, Postscript
- Java Virtual Machine
1 | infix: |
Goal: compiler translates
aexpinto stack machine instructions.
1 | Inductive sinstr : Type := |
Correct Proof
1 | Theorem s_compile_correct : forall (st : state) (e : aexp), |
To prove this, we need a stronger induction hypothesis (i.e. more general), so we state:
1 | Theorem s_execute_theorem : forall (st : state) (e : aexp) (stack : list nat) (prog : list sinstr), |
and go through!
IMP Break/Continue
1 | Inductive result : Type := |
The idea is that we can add a signal to notify the loop!
Fun to go through!
Slide Q & A
st =[c1;;c2] => st'
there would be intermediate thing after inversion so… we need determinism to prove this!
- (It won’t be even true in undetermincy)
the
WHILEone (would diverge)- true…how to prove?
- induction on derivation…!
- show contradiction for all cases
to prove
¬(∃st', ...), we intro the existentials and prove theFalse.
Auto
auto includes try
Proof with auto.Set Intro Auto
- 本文标题:「SF-LC」12 Imp
- 创建时间:2021-03-28 00:00:00
- 本文链接:posts/6b46.html
- 版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!