(***************)
(* EXPRESSIONS *)
(***************)
(* This is an expression tree with one binary operation `+` and * embedded literals in ℕ *)
Inductive expression_tree : Set :=
| Plus_ET : expression_tree -> expression_tree -> expression_tree
| Lit_ET : nat -> expression_tree.
(* This is an interpretation of the expression language, giving every * expression a denotation into ℕ *)
Fixpoint interp_expression_tree (e : expression_tree) : nat :=
match e with
| Plus_ET e1 e2 => interp_expression_tree e1 + interp_expression_tree e2
| Lit_ET n => n
end.
(* An equivalent way to represent these expression trees is by * flattening them into lists. This is ok to do because plus is * associative, and the zero literal is a unit for plus *)
Inductive expression_list : Set :=
| Plus_EL : nat -> expression_list -> expression_list
| Zero_EL : expression_list.
(* This "list-y" version of things also has an interpretation *)
Fixpoint interp_expression_list (e : expression_list) : nat :=
match e with
| Plus_EL n e' => n + interp_expression_list e'
| Zero_EL => 0
end.
(* A helper we need for the next thing... *)
Fixpoint append_expression_list (e1 : expression_list) (e2 : expression_list) : expression_list :=
match e1 with
| Plus_EL n e1' => Plus_EL n (append_expression_list e1' e2)
| Zero_EL => e2
end.
(* This is a constructive definition to support the claim that * expression trees can be compiled into expression lists. In fact, we * could prove a theorem than the denotation of `e` and `compile(e)` * are equal, and you will notice that in the proof you have to use * associativity and unit laws for plus. *)
Fixpoint compile_expression_tree (e : expression_tree) : expression_list :=
match e with
| Plus_ET e1 e2 => append_expression_list (compile_expression_tree e1) (compile_expression_tree e2)
| Lit_ET n => Plus_EL n Zero_EL
end.

Lemma interp_list': forall l1 l2, interp_expression_list (append_expression_list l1 l2) = interp_expression_list l1 + interp_expression_list l2.