Library Tait.WN
Require Export Apps.
Require Import Subst2.
Set Implicit Arguments.
Inductive WN : term -> term -> Prop :=
| WN_var : forall n l l', WNs l l' -> WN ([n];;l) ([n];;l')
| WN_abs : forall rho r s, WN r s -> WN (\rho,r) (\rho,s)
| WN_beta : forall rho (r s:term) l t,
WN ((sub r s);;l) t -> WN ((\rho,r);;(s::l)) t
with
WNs : list term -> list term -> Prop :=
| WNs_nil : WNs nil nil
| WNs_cons : forall r s l l', WN r s -> WNs l l' -> WNs (r::l) (s::l').
Hint Constructors WN.
Hint Constructors WNs.
Lemma WNs_app : forall l ll l' ll', WNs l l' -> WNs ll ll' ->
WNs (l++ll) (l'++ll').
Proof.
induction l; simpl; intros; inversion_clear H; simpl; auto.
Qed.
Hint Resolve WNs_app.
Lemma WNs_rev : forall l l',
WNs l l' -> WNs (rev l) (rev l').
Proof.
induction l; simpl; intros; inversion_clear H; simpl; auto.
Qed.
Lemma WNs_last: forall l l' r r',
WNs (l++r::nil) (l'++r'::nil) -> WNs l l' /\ WN r r'.
Proof.
intros.
generalize (WNs_rev H).
simpl_list.
inversion_clear 1.
generalize (WNs_rev H2).
simpl_list; auto.
Qed.
Here we define an ad-hoc induction principle (hidden in the doc)
Lemma WN_occurs :
forall r r', WN r r' -> forall k, occurs k r = false -> occurs k r' = false.
Proof.
intros r r' w.
set (P:= fun r r' => forall k, occurs k r = false -> occurs k r' = false).
change (P r r').
set (Q:= fun l l' => forall k, (existsb (occurs k) l = false) ->
(existsb (occurs k) l' = false)).
apply WN_WNs_ind with Q; unfold P, Q in *; clear P Q.
intros.
rewrite apps_occurs.
rewrite apps_occurs in H1.
destruct (orb_false_elim _ _ H1); clear H1.
rewrite H0; auto with bool.
intros.
simpl in *.
rewrite H0; auto.
intros.
simpl in H1.
rewrite apps_occurs in H1.
simpl in H1.
destruct (orb_false_elim _ _ H1); clear H1.
destruct (orb_false_elim _ _ H2); clear H2.
apply H0.
rewrite apps_occurs.
rewrite H3.
rewrite (orb_b_false).
apply sub_occurs; simpl; auto with bool.
simpl; simpl_arith; auto.
simpl; auto.
simpl; intros.
destruct (orb_false_elim _ _ H3); clear H3.
rewrite H0; auto.
rewrite H2; auto.
auto with bool.
Qed.
Lemma WN_subk :
forall r t, WN r t ->
forall (lk:list nat) sk r',
let rs := (map Var lk)#sk in
r = sub r' rs -> exists t', t = sub t' rs /\ WN r' t'.
