Section InterpImpProperties.
(** We can lift the underlying equational theory on [itree]s to include new equations for working with [interp_imp].  In particular, we have: - [interp_imp] respects [≈] - [interp_imp] commutes with [bind].  We could justify more equations than just the ones below.  For instance, _Imp_ programs also respect a coarser notation of equivalence for the [env] state.  We exploit this possibility to implement optimzations at the _Asm_ level (see AsmOptimizations.v). *)
Context {E': Type -> Type}.
Notation E := (ImpState +' E').
(** This interpreter is compatible with the equivalence-up-to-tau. *)
Global Instance eutt_interp_imp {R}:
Proper (@eutt E R R eq ==> eq ==> @eutt E' (prod (env) R) (prod _ R) eq)
interp_imp.

(** [interp_imp] commutes with [bind]. *)
Lemma interp_imp_bind: forall {R S} (t: itree E R) (k: R -> itree E S) (g : env),
(interp_imp (ITree.bind t k) g)
≅ (ITree.bind (interp_imp t g) (fun '(g',  x) => interp_imp (k x) g')).