(*************************************************************************)
(** * Opening *)
(*************************************************************************)
(** Opening replaces an index with a term.  It corresponds to informal substitution for a bound variable, such as in the rule for beta reduction.  Note that only "dangling" indices (those that do not refer to any abstraction) can be opened.  Opening has no effect for terms that are locally closed.  Natural numbers are just an inductive datatype with two constructors: [O] (as in the letter 'oh', not 'zero') and [S], defined in Coq.Init.Datatypes.  Coq allows literal natural numbers to be written using standard decimal notation, e.g., 0, 1, 2, etc. The notation [k == i] is the decidable equality function for natural numbers (cf. [Coq.Peano_dec.eq_nat_dec]).  This notation is defined in the Metatheory library.  We make several simplifying assumptions in defining [open_rec].  First, we assume that the argument [u] is locally closed.  This assumption simplifies the implementation since we do not need to shift indices in [u] when passing under a binder.  Second, we assume that this function is initially called with index zero and that zero is the only unbound index in the term.  This eliminates the need to possibly subtract one in the case of indices.  There is no need to worry about variable capture because bound variables are indices. *)
Fixpoint open_rec (k : nat) (u : exp)(e : exp)
{struct e} : exp :=
match e with
| bvar i => if k == i then u else (bvar i)
| fvar x => fvar x
| abs t e1 => abs t (open_rec (S k) u e1)
| app e1 e2 => app (open_rec k u e1) (open_rec k u e2)
end.
(** Many common applications of opening replace index zero with an expression or variable.  The following definition provides a convenient shorthand for such uses.  Note that the order of arguments is switched relative to the definition above.  For example, [(open e x)] can be read as "substitute the variable [x] for index [0] in [e]" and "open [e] with the variable [x]." Recall that the coercions above let us write [x] in place of [(fvar x)]. *)
Definition open e u := open_rec 0 u e.
(** This next demo shows the operation of [open].  For example, the locally nameless representation of the term (\y. (\x. (y x)) y) is [abs (app (abs (app 1 0)) 0)].  To look at the body without the outer abstraction, we need to replace the indices that refer to that abstraction with a name.  Therefore, we show that we can open the body of the abs above with Y to produce [app (abs (app Y 0)) Y)]. *)

Lemma demo_open :
open (app (abs typ_base (app 1 0)) 0) Y =
(app (abs typ_base (app Y 0)) Y).