I was trying out the first example (untyped) from chapter 2 of the CPDT book under the section Arithmetic Expressions Over Natural Numbers and did

```
(** * Source language **)
Inductive binop : Set := Plus | Mult.
Inductive exp : Set :=
| Const : nat -> exp
| Binop : binop -> exp -> exp -> exp.
Definition binopDenote (op : binop) : nat -> nat -> nat :=
match op with
| Plus => plus (* Same as Nat.add *)
| Mult => mult (* Same as Nat.mul *)
end.
Fixpoint expDenote (e : exp) : nat :=
match e with
| Const n => n
| Binop op e1 e2 => (binopDenote op) (expDenote e1) (expDenote e2)
end.
(** * Target language **)
Inductive instr : Set :=
| iConst : nat -> instr
| iBinop : binop -> instr.
Definition stack : Set := list nat.
Definition instrDenote (i : instr) (s : stack) : option stack :=
match i with
| iConst n => Some (n :: s)
| iBinop b =>
match s with
| (s2 :: s1 :: ss) => (* Was changed from (s1::s2::ss) here *)
let nval := ((binopDenote b) s1 s2) in
Some (nval :: ss)
| _ => None (* Stack prematurely empty! *)
end
end.
Definition prog : Set := list instr.
Fixpoint progDenote (p : prog) (s : stack) : option stack :=
match p with
| (px::pxs) =>
match (instrDenote px s) with
| Some s' => progDenote pxs s'
| None => None
end
| _ => Some s
end.
(** * Translation *)
Fixpoint compile (e : exp) : list instr :=
match e with
| Const n => [iConst n]%list
| Binop op e1 e2 => (compile e2) ++ (compile e1) ++ [iBinop op]%list
end.
```

I had made a change in the definition of `instrDenote`

in the match case of `iBinop`

from something like

```
| iBinop b =>
match s with
| (s1 :: s2 :: ss) =>
let nval := ((binopDenote b) s1 s2) in
Some (nval :: ss)
| _ => None
end
```

to

```
| iBinop b =>
match s with
| (s2 :: s1 :: ss) =>
let nval := ((binopDenote b) s1 s2) in
Some (nval :: ss)
| _ => None
end
```

ie, the order in which elements are taken from the stack was reversed.

But with this change, I couldn't prove the 'translation correctness' proof:

```
Theorem foobar : forall (e : exp) (p : prog) (s : stack),
progDenote ((compile e) ++ p) s = progDenote p ((expDenote e)::s).
Proof.
induction e.
- intros.
unfold compile.
reflexivity.
- intros.
unfold compile.
fold compile.
unfold expDenote.
fold expDenote.
rewrite app_assoc_reverse.
rewrite IHe2.
rewrite app_assoc_reverse.
rewrite IHe1.
unfold progDenote at 1.
simpl.
fold progDenote.
```

the goal at this point would be

```
1 subgoal
b : binop
e1, e2 : exp
IHe1 : forall (p : prog) (s : stack),
progDenote (compile e1 ++ p) s = progDenote p (expDenote e1 :: s)
IHe2 : forall (p : prog) (s : stack),
progDenote (compile e2 ++ p) s = progDenote p (expDenote e2 :: s)
p : prog
s : stack
========================= (1 / 1)
progDenote p (binopDenote b (expDenote e2) (expDenote e1) :: s) =
progDenote p (binopDenote b (expDenote e1) (expDenote e2) :: s)
```

and the error was

```
In environment
b : binop
e1, e2 : exp
IHe1 : forall (p : prog) (s : stack),
progDenote (compile e1 ++ p) s = progDenote p (expDenote e1 :: s)
IHe2 : forall (p : prog) (s : stack),
progDenote (compile e2 ++ p) s = progDenote p (expDenote e2 :: s)
p : prog
s : stack
Unable to unify
"progDenote p (binopDenote b (expDenote e1) (expDenote e2) :: s)"
with "progDenote p (binopDenote b (expDenote e2) (expDenote e1) :: s)".
```

But if the change was not made and the order of elements taken from the stack wasn't changed in `instrDenote`

, the proof would end all right.

Was the change that I made erroneous? Or is all I need some change in the proof steps?

I’d say the change is erroneous. In your snippet, the proof can be completed despite your change by proving that `binopDenote b`

is commutative. However, that seems an accident: once you extend the language with subtraction, that will stop being the case. At that point, `instrDenote`

will have to fetch the elements in the correct order.

The reason is that the output of `compile (Binop op e1 e2)`

evaluates and pushes `e2`

to `s2`

, then it evaluates `e1`

to `s1`

and pushes that on top, so the produced stack will have `s1`

on top, then `s2`

.

Okay. So changing the order of 'compilation' of expressions to make it

```
Fixpoint compile (e : exp) : list instr :=
match e with
| Const n => [iConst n]%list
| Binop op e1 e2 => (compile e1) ++ (compile e2) ++ [iBinop op]%list
(* changed from
| Binop op e1 e2 => (compile e2) ++ (compile e1) ++ [iBinop op]%list
*)
end.
```

would set it right? The proof was able to finish after that second change.

I had another small doubt related to this. Could help me with this as well?

Right after the `unfold compile.`

in the first subgoal of the induction, when the goal was

```
1 Subgoal
(1 unfocused at this level)
n : nat
p : prog
s : stack
========================= (1 / 1)
progDenote ([iConst n] ++ p) s = progDenote p (expDenote (Const n) :: s)
```

I did `simpl.`

after which the goal became

```
1 subgoal
(1 unfocused at this level)
n : nat
p : prog
s : stack
========================= (1 / 1)
progDenote p (n :: s) = progDenote p (n :: s)
```

Both `progDenote ([iConst n] ++ p) s`

and `progDenote p (expDenote (Const n) :: s)`

became `progDenote p (n :: s)`

.

`simpl.`

does some evaluations, right?

I understand `progDenote p (expDenote (Const n) :: s)`

becoming `progDenote p (n :: s)`

as `expDenote (Const n)`

gives `n`

.

But how did `progDenote ([iConst n] ++ p) s`

become `progDenote p (n :: s)`

as well?

Same thing. By evaluation of the definitions of `++`

, `progDenote`

, and `instrDenote`

.

Is it that `simpl.`

evaluates `progDenote`

partially or something? I mean, `progDenote`

is still there whereas in the other case with `expDenote`

, `expDenote`

disappeared once its definition was used.

"evaluate partially" is not wrong; `simpl`

has pretty complex heuristic to choose what term to produce.

Yes, it is partial evaluation. But in fact, it is more like weak normalization. Coq's evaluation rules only unfold a fixpoint function if the argument has a constructor in head position. Since `p`

does not, `progDenote`

stays around.

(The so-called "iota-reduction" rule.)

Had heard of iota rule. But had never really looked it up. Thanks guys!

Ju-sh has marked this topic as resolved.

Last updated: Oct 03 2023 at 04:02 UTC