Library UntypedLambda

Untyped lambda terms in de Bruijn representation
Require Import Setoid Equivalence Morphisms.
Set Implicit Arguments.
Unset Strict Implicit.
Open Scope equiv_scope.

Inductive term :=
| Var (x : nat)
| App (s t : term)
| Lam (s : term).
Coercion Var : nat >-> term.
Coercion App : term >-> Funclass.

Implicit Types (s t : term) (sigma tau : nat -> term) (xi : nat -> nat).

Function composition

Definition funcomp {A B C : Type} (f : A -> B) (g : B -> C) x := g(f(x)).
Arguments funcomp {A B C} f g x /.

Delimit Scope subst_scope with subst.
Open Scope subst_scope.

Reserved Notation "sigma >> tau" (at level 56, left associativity).
Notation "f >>> g" := (funcomp f g)
  (at level 56, left associativity) : subst_scope.

Stream cons

Definition scons {X : Type} (s : X) (xs : nat -> X) (x : nat) : X :=
  match x with S y => xs y | _ => s end.
Notation "s .: xr" := (scons s xr)
  (at level 55, sigma at level 56, right associativity) : subst_scope.

Lemma scons_comp X Y (x : X) (f : nat -> X) (g : X -> Y) :
  (x .: f) >>> g === (g x) .: (f >>> g).
Proof. intros [|n]; reflexivity. Qed.

Instantiation

Definition upr xi := 0 .: (xi >>> S).

Fixpoint rename xi s : term :=
  match s with
  | Var n => xi n
  | App s t => App (rename xi s) (rename xi t)
  | Lam s => Lam (rename (upr xi) s)
  end.

Definition up sigma := Var 0 .: (sigma >>> rename S).
Arguments up sigma x /.

Fixpoint subst sigma s :=
  match s with
  | Var n => sigma n
  | App s t => App (subst sigma s) (subst sigma t)
  | Lam s => Lam (subst (up sigma) s)
  end.

Definition ren xi := xi >>> Var.

Definition scomp sigma tau := sigma >>> subst tau.
Arguments scomp sigma tau x /.
Notation "sigma >> tau" := (scomp sigma tau).

Notation "s .[ sigma ]" := (subst sigma s)
  (at level 2, sigma at level 200, left associativity,
   format "s .[ sigma ]" ) : subst_scope.
Notation "s .[ t /]" := (subst (t .: Var) s)
  (at level 2, t at level 200, left associativity,
   format "s .[ t /]") : subst_scope.

Extensionality properties

Instance subst_proper :
  Proper (pointwise_relation nat eq ==> eq ==> eq) subst.
Proof.
  intros sigma tau eq1 s t eq2. subst t. revert sigma tau eq1.
  induction s; simpl; intros.
  - apply eq1.
  - f_equal. now apply IHs1. now apply IHs2.
  - f_equal. apply IHs. intros [|n]; simpl. reflexivity.
    unfold up. simpl. now rewrite eq1.
Qed.

Instance scomp_proper :
  Proper (pointwise_relation nat eq ==> pointwise_relation nat eq ==> pointwise_relation nat eq) scomp.
Proof.
  intros sigma sigma´ eq1 tau tau´ eq2 n. unfold scomp. simpl.
  now rewrite eq1, eq2.
Qed.

Instance scons_proper X :
  Proper (eq ==> pointwise_relation nat eq ==> pointwise_relation nat eq) (@scons X).
Proof.
  intros x y eq1 xs ys eq2 [|n]; simpl. apply eq1. apply eq2.
Qed.

Renaming is a special case of substitution

Lemma upr_up xi : up xi === upr xi.
Proof. now intros []. Qed.

Lemma rename_subst xi :
  rename xi === subst xi.
Proof.
  intros s. revert xi. induction s; simpl; intros.
  - reflexivity.
  - now rewrite IHs1, IHs2.
  - now rewrite IHs, <- upr_up.
Qed.

Lemma upE sigma :
  up sigma === Var 0 .: (sigma >> S).
Proof.
  intros [|x]; simpl; auto. apply rename_subst.
Qed.

Var is the identity substitution

Lemma up_id : up Var === Var.
Proof. now intros []. Qed.

Lemma subst_id s : s.[Var] = s.
Proof.
  induction s; simpl; eauto. now rewrite IHs1, IHs2.
  now rewrite up_id, IHs.
Qed.

Instantiation/Composition of substitutions forms a monoid action

Lemma subst_ren sigma xi s :
  s.[xi].[sigma] = s.[xi >>> sigma].
Proof.
  revert sigma xi. induction s; simpl; intros.
  - reflexivity.
  - now rewrite IHs1, IHs2.
  - rewrite upr_up, IHs. unfold upr. now rewrite scons_comp.
Qed.

Lemma ren_subst xi sigma s :
  s.[sigma].[xi] = s.[sigma >> xi].
Proof.
  revert xi sigma. induction s; simpl; intros.
  - reflexivity.
  - now rewrite IHs1, IHs2.
  - rewrite upr_up, IHs. do 2 f_equiv; intros [|n]; simpl.
    reflexivity. now rewrite !rename_subst, !subst_ren.
Qed.

Lemma up_comp sigma tau :
  up sigma >> up tau === up (sigma >> tau).
Proof.
  intros [|n]; simpl. reflexivity. rewrite !rename_subst.
  rewrite subst_ren, ren_subst. f_equiv; intros m. simpl.
  apply rename_subst.
Qed.

Lemma subst_comp sigma tau s :
  s.[sigma].[tau] = s.[sigma >> tau].
Proof.
  revert sigma tau. induction s; simpl; intros.
  - reflexivity.
  - now rewrite IHs1, IHs2.
  - now rewrite IHs, up_comp.
Qed.

Derived substitution lemmas

Lemma scons_scomp s sigma tau :
  (s .: sigma) >> tau === s.[tau] .: (sigma >> tau).
Proof. now intros []. Qed.

Lemma subst_extend sigma s :
  up sigma >> (s .: Var) === s .: sigma.
Proof.
  rewrite upE, scons_scomp; intros [|n]; simpl.
  - reflexivity.
  - now rewrite subst_comp, subst_id.
Qed.

Lemma subst_beta s t sigma :
  s.[up sigma].[t.[sigma]/] = s.[t/].[sigma].
Proof.
  now rewrite !subst_comp, subst_extend, scons_scomp.
Qed.