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]. *)
(* ---------------------------------------------------------------------------- *)
(* Reduction semantics. *)
Inductive red : term -> term -> Prop :=
| RedBeta:
forall t1 t2 t,
subst t2 0 t1 = t ->
red (TApp (TAbs t1) t2) t
| RedContextTAbs:
forall t1 t2,
red t1 t2 ->
red (TAbs t1) (TAbs t2)
| RedContextTAppLeft:
forall t1 t2 t,
red t1 t2 ->
red (TApp t1 t) (TApp t2 t)
| RedContextTAppRight:
forall t1 t2 t,
red t1 t2 ->
red (TApp t t1) (TApp t t2).
(* The reduction judgement is compatible with weakening. *)
(* ---------------------------------------------------------------------------- *)
(* Working with closedness. *)
(* Again, we prove the following lemmas only in order to illustrate the use of the tactic [inversion_closed]. *)
(* Reduction preserves closedness. *)
(* ---------------------------------------------------------------------------- *)
(* Simple types. *)
(* These types do not contain any variables. They have no binding structure. *)
Inductive ty :=
| TyIota: ty
| TyArrow: ty -> ty -> ty.
(* The typing judgement of the simply-typed lambda-calculus. *)
Inductive j : env ty -> term -> ty -> Prop :=
| JVar:
forall E x T,
lookup x E = Some T ->
j E (TVar x) T
| JAbs:
forall E t T1 T2,
j (insert 0 T1 E) t T2 ->
j E (TAbs t) (TyArrow T1 T2)
| JApp:
forall E t1 t2 T1 T2,
j E t1 (TyArrow T1 T2) ->
j E t2 T1 ->
j E (TApp t1 t2) T2.
Hint Constructors j : j.
(* ---------------------------------------------------------------------------- *)
(* The typing judgement is compatible with weakening, i.e., inserting a new term variable. *)
(* The typing judgement is compatible with substitution, i.e., substituting a well-typed term for a term variable. *)
(* The typing judgement is preserved by reduction. Note that this is proved for an arbitrary environment [E]: we do not restrict our attention to closed terms. *)
(* ---------------------------------------------------------------------------- *)
(* The following lemmas are not needed here, but could be useful in other settings. *)
(* A term that is well-typed under the empty environment is closed. *)
(* A term that is well-typed under the empty environment is well-typed under every environment. *)

Lemma j_agree:
forall E1 t T,
j E1 t T ->
forall E2 k,
agree E1 E2 k ->
length E1 <= k ->
j E2 t T.