133 lines
3.6 KiB
Text
133 lines
3.6 KiB
Text
/-!
|
|
# Arithmetic expressions for a simple imperative language.
|
|
-/
|
|
|
|
namespace imp
|
|
open tactic
|
|
|
|
/-- Variable names -/
|
|
@[reducible] def uname := string
|
|
|
|
/--
|
|
#brief Arithmetic expressions abstract syntax tree.
|
|
|
|
We encode x + 1 as
|
|
```
|
|
#check aexp.plus (aexp.var "x") (aexp.val 1)
|
|
```
|
|
-/
|
|
inductive aexp
|
|
| val : nat → aexp
|
|
| var : uname → aexp
|
|
| plus : aexp → aexp → aexp
|
|
|
|
/-- #brief Arithmetic expressions have decidable equality. -/
|
|
instance : decidable_eq aexp :=
|
|
by mk_dec_eq_instance
|
|
|
|
/-- #brief Value assigned to variables. -/
|
|
@[reducible] def value := nat
|
|
|
|
/-- #brief The state is a mapping from variable names to their values. -/
|
|
def state := uname → value
|
|
|
|
open aexp
|
|
|
|
/--
|
|
#brief Given an arithmetic expression and a state, this function returns the
|
|
value for the expression.
|
|
|
|
```
|
|
example : aval (plus (val 3) (var "x")) (λ x, 0) = 3 :=
|
|
rfl
|
|
```
|
|
See [`aexp`](#imp.aexp)
|
|
-/
|
|
def aval : aexp → state → value
|
|
| (val n) s := n
|
|
| (var x) s := s x
|
|
| (plus a₁ a₂) s := aval a₁ s + aval a₂ s
|
|
|
|
/--
|
|
#brief Update the state with then entry `x -> v`.
|
|
We say we are assigning `v` to `x`.
|
|
-/
|
|
def updt (s : state) (x : uname) (v : value) : state :=
|
|
λ y, if x = y then v else s y
|
|
|
|
/--
|
|
#brief Very basic constant folding simplification procedure.
|
|
For example, it reduces subexpressions such as (3 + 2) to 5.
|
|
-/
|
|
def asimp_const : aexp → aexp
|
|
| (val n) := val n
|
|
| (var x) := var x
|
|
| (plus a₁ a₂) :=
|
|
match asimp_const a₁, asimp_const a₂ with
|
|
| val n₁, val n₂ := val (n₁ + n₂)
|
|
| b₁, b₂ := plus b₁ b₂
|
|
end
|
|
|
|
/-!
|
|
_Remark_: we can prove by reflexivity the fact that the constant folder simplifies `(2+3)+x` into `5+x`.
|
|
```
|
|
example : asimp_const (plus (plus (val 2) (val 3)) (var "x")) = plus (val 5) (var "x") :=
|
|
rfl
|
|
```
|
|
-/
|
|
|
|
/-- #brief Prove that constant folding preserves the value of an artihmetic expressions. -/
|
|
lemma aval_asimp_const (a : aexp) (s : state) : aval (asimp_const a) s = aval a s :=
|
|
begin
|
|
induction a with n x a₁ a₂ ih₁ ih₂,
|
|
repeat {reflexivity},
|
|
{unfold asimp_const aval,
|
|
rewrite [-ih₁, -ih₂],
|
|
cases (asimp_const a₁),
|
|
repeat {cases (asimp_const a₂), repeat {reflexivity}}}
|
|
end
|
|
|
|
/--
|
|
#brief Alternative proof without tactics that constant folding preserves
|
|
the value of an arithmetic expression.
|
|
|
|
This alternative proof is more verbose because we are essentially writing
|
|
the proof term.
|
|
-/
|
|
lemma aval_asimp_const₂ : ∀ (a : aexp) (s : state), aval (asimp_const a) s = aval a s
|
|
| (val n) s := rfl
|
|
| (var x) s := rfl
|
|
| (plus a₁ a₂) s :=
|
|
show aval (asimp_const (plus a₁ a₂)) s = aval a₁ s + aval a₂ s, from
|
|
suffices aval (asimp_const._match_1 (asimp_const a₁) (asimp_const a₂)) s = aval (asimp_const a₁) s + aval (asimp_const a₂) s, from
|
|
aval_asimp_const₂ a₁ s ▸ aval_asimp_const₂ a₂ s ▸ this,
|
|
match asimp_const a₁, asimp_const a₂ with
|
|
| val _, val _ := rfl
|
|
| val _, var _ := rfl
|
|
| val _, plus _ _ := rfl
|
|
| var _, val _ := rfl
|
|
| var _, var _ := rfl
|
|
| var _, plus _ _ := rfl
|
|
| plus _ _, val _ := rfl
|
|
| plus _ _, var _ := rfl
|
|
| plus _ _, plus _ _ := rfl
|
|
end
|
|
|
|
/--
|
|
#brief Alternative proof that mixes proof terms and tactics.
|
|
|
|
See [`asimp_const`](#imp.asimp_const)
|
|
-/
|
|
lemma aval_asimp_const₃ : ∀ (a : aexp) (s : state), aval (asimp_const a) s = aval a s
|
|
| (val n) s := rfl
|
|
| (var x) s := rfl
|
|
| (plus a₁ a₂) s :=
|
|
begin
|
|
note h₁ := aval_asimp_const₃ a₁ s,
|
|
note h₂ := aval_asimp_const₃ a₂ s,
|
|
unfold asimp_const aval,
|
|
rewrite [-h₁, -h₂],
|
|
cases (asimp_const a₁); cases (asimp_const a₂); repeat {reflexivity}
|
|
end
|
|
|
|
end imp
|