(** The tactic [repeat T] also does not have any upper bound on the number of times it applies [T].  If [T] is a tactic that always succeeds, then repeat [T] will loop forever (e.g., [repeat simpl] loops forever, since [simpl] always succeeds).  While evaluation in Coq's term language, Gallina, is guaranteed to terminate, tactic evaluation is not!  This does not affect Coq's logical consistency, however, since the job of [repeat] and other tactics is to guide Coq in constructing proofs; if the construction process diverges, this simply means that we have failed to construct a proof, not that we have constructed a wrong one. *)
(** **** Exercise: 3 stars (optimize_0plus_b)  *)
(** Since the [optimize_0plus] transformation doesn't change the value of [aexp]s, we should be able to apply it to all the [aexp]s that appear in a [bexp] without changing the [bexp]'s value.  Write a function which performs that transformation on [bexp]s, and prove it is sound.  Use the tacticals we've just seen to make the proof as elegant as possible. *)
(* REPLACE THIS LINE WITH ":= _your_definition_ ." *). Admitted.  Theorem optimize_0plus_b_sound : forall b, beval (optimize_0plus_b b) = beval b.  (** (Note the [Require Import Coq.omega.Omega.] at the top of the file.) *)
(* ================================================================= *)
(** ** A Few More Handy Tactics *)
(** Finally, here are some miscellaneous tactics that you may find convenient.  - [clear H]: Delete hypothesis [H] from the context.  - [subst x]: Find an assumption [x = e] or [e = x] in the context, replace [x] with [e] throughout the context and current goal, and clear the assumption.  - [subst]: Substitute away _all_ assumptions of the form [x = e] or [e = x].  - [rename... into...]: Change the name of a hypothesis in the proof context.  For example, if the context includes a variable named [x], then [rename x into y] will change all occurrences of [x] to [y].  - [assumption]: Try to find a hypothesis [H] in the context that exactly matches the goal; if one is found, behave like [apply H].  - [contradiction]: Try to find a hypothesis [H] in the current context that is logically equivalent to [False].  If one is found, solve the goal.  - [constructor]: Try to find a constructor [c] (from some [Inductive] definition in the current environment) that can be applied to solve the current goal.  If one is found, behave like [apply c].  We'll see examples below. *)
(* ################################################################# *)
(** * Evaluation as a Relation *)
(** We have presented [aeval] and [beval] as functions defined by [Fixpoint]s.  Another way to think about evaluation -- one that we will see is often more flexible -- is as a _relation_ between expressions and their values.  This leads naturally to [Inductive] definitions like the following one for arithmetic expressions... *)
Inductive aevalR : aexp -> nat -> Prop :=
| E_ANum  : forall (n: nat),
aevalR (ANum n) n
| E_APlus : forall (e1 e2: aexp) (n1 n2: nat),
aevalR e1 n1 ->
aevalR e2 n2 ->
aevalR (APlus e1 e2) (n1 + n2)
| E_AMinus: forall (e1 e2: aexp) (n1 n2: nat),
aevalR e1 n1 ->
aevalR e2 n2 ->
aevalR (AMinus e1 e2) (n1 - n2)
| E_AMult : forall (e1 e2: aexp) (n1 n2: nat),
aevalR e1 n1 ->
aevalR e2 n2 ->
aevalR (AMult e1 e2) (n1 * n2).
(** It will be convenient to have an infix notation for [aevalR].  We'll write [e \\ n] to mean that arithmetic expression [e] evaluates to value [n].  (This notation is one place where the limitation to ASCII symbols becomes a little bothersome.  The standard notation for the evaluation relation is a double down-arrow.  We'll typeset it like this in the HTML version of the notes and use a double slash as the closest approximation in [.v] files.)  *)
Notation "e '\\' n"
:= (aevalR e n)
(at level 50, left associativity)
: type_scope.
End aevalR_first_try.
(** In fact, Coq provides a way to use this notation in the definition of [aevalR] itself.  This reduces confusion by avoiding situations where we're working on a proof involving statements in the form [e \\ n] but we have to refer back to a definition written using the form [aevalR e n].  We do this by first "reserving" the notation, then giving the definition together with a declaration of what the notation means. *)
Reserved Notation "e '\\' n" (at level 50, left associativity).
Inductive aevalR : aexp -> nat -> Prop :=
| E_ANum : forall (n:nat),
(ANum n) \\ n
| E_APlus : forall (e1 e2: aexp) (n1 n2 : nat),
(e1 \\ n1) -> (e2 \\ n2) -> (APlus e1 e2) \\ (n1 + n2)
| E_AMinus : forall (e1 e2: aexp) (n1 n2 : nat),
(e1 \\ n1) -> (e2 \\ n2) -> (AMinus e1 e2) \\ (n1 - n2)
| E_AMult :  forall (e1 e2: aexp) (n1 n2 : nat),
(e1 \\ n1) -> (e2 \\ n2) -> (AMult e1 e2) \\ (n1 * n2)
where "e '\\' n" := (aevalR e n) : type_scope.
(* ================================================================= *)
(** ** Inference Rule Notation *)
(** In informal discussions, it is convenient to write the rules for [aevalR] and similar relations in the more readable graphical form of _inference rules_, where the premises above the line justify the conclusion below the line (we have already seen them in the [IndProp] chapter). *)
(** For example, the constructor [E_APlus]...  | E_APlus : forall (e1 e2: aexp) (n1 n2: nat), aevalR e1 n1 -> aevalR e2 n2 -> aevalR (APlus e1 e2) (n1 + n2)  ...would be written like this as an inference rule:  e1 \\ n1 e2 \\ n2 --------------------                         (E_APlus) APlus e1 e2 \\ n1+n2 *)
(** Formally, there is nothing deep about inference rules: they are just implications.  You can read the rule name on the right as the name of the constructor and read each of the linebreaks between the premises above the line (as well as the line itself) as [->].  All the variables mentioned in the rule ([e1], [n1], etc.) are implicitly bound by universal quantifiers at the beginning. (Such variables are often called _metavariables_ to distinguish them from the variables of the language we are defining.  At the moment, our arithmetic expressions don't include variables, but we'll soon be adding them.)  The whole collection of rules is understood as being wrapped in an [Inductive] declaration.  In informal prose, this is either elided or else indicated by saying something like "Let [aevalR] be the smallest relation closed under the following rules...". *)
(** For example, [\\] is the smallest relation closed under these rules:  -----------                               (E_ANum) ANum n \\ n  e1 \\ n1 e2 \\ n2 --------------------                         (E_APlus) APlus e1 e2 \\ n1+n2  e1 \\ n1 e2 \\ n2 ---------------------                        (E_AMinus) AMinus e1 e2 \\ n1-n2  e1 \\ n1 e2 \\ n2 --------------------                         (E_AMult) AMult e1 e2 \\ n1*n2 *)
(* ================================================================= *)
(** ** Equivalence of the Definitions *)
(** It is straightforward to prove that the relational and functional definitions of evaluation agree: *)

Theorem aeval_iff_aevalR : forall a n,
(a \\ n) <-> aeval a = n.