Set Implicit Arguments.
Require Export Coq.Program.Equality.
(* ---------------------------------------------------------------------------- *)
(* The syntax of untyped lambda-terms. *)
Inductive term :=
| TVar: nat -> term
| TAbs: term -> term
| TApp: term -> term -> term.
(* ---------------------------------------------------------------------------- *)
(* The following definitions allow us to use the [DeBruijn] library. In particular, [traverse_term] defines the binding structure of terms. *)
Instance Var_term : Var term := {
var := TVar (* avoid eta-expansion *)
}.
Fixpoint traverse_term (f : nat -> nat -> term) l t :=
match t with
| TVar x =>
f l x
| TAbs t =>
TAbs (traverse_term f (1 + l) t)
| TApp t1 t2 =>
TApp (traverse_term f l t1) (traverse_term f l t2)
end.
Instance Traverse_term : Traverse term term := {
traverse := traverse_term
}.
Instance TraverseVarInjective_term : @TraverseVarInjective term _ term _.
Instance TraverseFunctorial_term : @TraverseFunctorial term _ term _.
Instance TraverseRelative_term : @TraverseRelative term term _.
Instance TraverseIdentifiesVar_term : @TraverseIdentifiesVar term _ _.
Instance TraverseVarIsIdentity_term : @TraverseVarIsIdentity term _ term _.
(* ---------------------------------------------------------------------------- *)
(* The following lemmas characterize [lift] and [subst]. In principle, the user does not need to explicitly state these lemmas, and that is fortunate. Here, we prove these lemmas only in order to illustrate how the tactics [simpl_lift] and [simpl_subst] can simplify applications of [lift] and [subst]. *)

Lemma subst_TAbs:
forall v k t,
subst v k (TAbs t) = TAbs (subst (shift 0 v) (1 + k) t).