(* Higher-order syntax for the untyped lambda-calculus Venanzio Capretta and Amy Felty March 2006 see the article "Combining de Bruijn Indices and Higher-Order Abstract Syntax in Coq" *) Require Import deBruijn. Inductive LCcon: Set := LCapp: LCcon | LCabs: LCcon. Definition lexp: Set := expr LCcon. (* Characterization of the correct terms of the lambda-calculus. *) Fixpoint term_check (e:lexp): bool := match e with (VAR v) => true | (BND b) => true | (APP (CON LCabs) (ABS e)) => term_check e | (APP (APP (CON LCapp) e1) e2) => andb (term_check e1) (term_check e2) | _ => false end. Definition tcheck: lexp -> Prop := fun e => Is_true (term_check e). (* Theorem 1 from article: Induction principle on correct expressions. *) Lemma tcheck_ind: forall (P: lexp -> Prop), (forall v, P (VAR _ v)) -> (forall i, P (BND _ i)) -> (forall e, P e -> P (APP (CON LCabs) (ABS e))) -> (forall e1 e2, P e1 -> P e2 -> P (APP (APP (CON LCapp) e1) e2)) -> forall e, tcheck e -> P e. Proof. intros P Hvar Hbnd Habs Happ e'. apply expr_star_ind with (con := LCcon) (P := fun e => tcheck e -> P e). intro e; case e. intros l IH h; elim h. intros v IH h; apply Hvar. intros i IH h; apply Hbnd. intros a; case a. intros l; case l. intros b IH h; elim h. (* ABS *) intro b; case b. intros l1 IH h; elim h. intros v IH h; elim h. intros i IH h; elim h. intros b1 b2 IH h; elim h. intros b1 IH h; apply Habs. inversion_clear IH. inversion_clear H2. apply H3; exact h. intros v b IH h; elim h. intros i b IH h; elim h. intro a1; case a1. intro l; case l. (* APP *) intros a2 b IH h; inversion_clear IH. unfold tcheck in h; simpl in h. apply Happ. inversion_clear H0. apply H5. unfold tcheck; eapply Is_true_conj_left; apply h. apply H1. unfold tcheck; eapply Is_true_conj_right; apply h. intros a2 b IH h; elim h. intros v a2 b IH h; elim h. intros i a2 b IH h; elim h. intros a2 a3 a4 b IH h; elim h. intros a2 a3 b IH h; elim h. intros a2 b IH h; elim h. intros a IH h; elim h. Qed. (* Definition of lambda-terms: expression with a proof of correctness. *) Record term: Set := mk_term { t_expr: lexp; t_check: Is_true (term_check t_expr) }. Lemma bshift_aux_check: forall e, tcheck e -> forall i, tcheck (bshift_aux e i). Proof. intros e' h'; apply tcheck_ind with (P := fun e => forall i, tcheck (bshift_aux e i)). (* Var *) intros v i; red; simpl. exact I. (* Bind *) intros j i; red; simpl. case (le_lt_dec i j); intro; exact I. (* Abs *) intros e IH i; red; simpl; apply IH. (* App *) intros e1 e2 IH1 IH2 i; red; simpl. apply Is_true_conj; [apply IH1 | apply IH2]. exact h'. Qed. Lemma bshift_check: forall e, tcheck e -> tcheck (bshift e). Proof. intros e h; unfold bshift; apply bshift_aux_check; exact h. Qed. Lemma bsubst_check: forall e1 j e2, tcheck e1 -> tcheck e2 -> tcheck (bsubst e1 j e2). Proof. intros e1 j e2 h1; generalize e2; generalize j; clear e2; clear j. apply tcheck_ind with (P := fun e1 => forall j e2, tcheck e2 -> tcheck (bsubst e1 j e2)). (* VAR *) intros v j e2 h2; exact I. (* BND *) intros i j e2 h2; simpl. case (bnd_dec i j). intros _; exact h2. intros _; exact I. (* ABS *) intros e IH j e2 h2. change (tcheck (bsubst e (S j) (bshift e2))). apply IH. apply bshift_check; exact h2. (* APP *) intros a b IHa IHb j e2 h2. unfold tcheck; simpl. apply Is_true_conj. apply IHa; exact h2. apply IHb; exact h2. exact h1. Qed. Lemma ebind_check: forall e, tcheck e -> forall w j, tcheck (ebind w j e). Proof. intros e' h'. apply tcheck_ind with (P := fun e => forall w j, tcheck (ebind w j e)). (* VAR *) intros v w j; simpl. case (var_dec v w). intros _; exact I. intros _; exact I. (* BND *) intros i w j; simpl. case (bnd_dec i j). intros _; exact I. intros _; exact I. (* ABS *) unfold tcheck; intros e IH w j; simpl. apply IH. (* APP *) unfold tcheck; intros e1 e2 IH1 IH2 w j; simpl. apply Is_true_conj; [apply IH1 | apply IH2]. exact h'. Qed. Lemma term_check_unicity: forall (e:lexp)(c1 c2: tcheck e), c1=c2. Proof. intro e; unfold tcheck. case (term_check e); simpl. intros [] []; trivial. intro c1; case c1. Qed. Lemma mk_term_unicity: forall (e1 e2:lexp), e1=e2 -> forall (c1:tcheck e1)(c2:tcheck e2), mk_term e1 c1 = mk_term e2 c2. Proof. intros e1 e2 Heq; rewrite Heq. intros c1 c2; rewrite (term_check_unicity e2 c1 c2). trivial. Qed. (* Lemma 2 from article. *) Lemma term_unicity: forall a1 a2, (t_expr a1)=(t_expr a2) -> a1=a2. Proof. intros [e1 c1] [e2 c2] Heq; simpl in Heq. apply mk_term_unicity. exact Heq. Qed. (* Definition of the higher-order syntax of lambda-terms. *) Definition Var (i:var): term := mk_term (VAR _ i) I. Definition Bind (i:bnd): term := mk_term (BND _ i) I. Definition tApp (a1 a2:term): term := mk_term (APP (APP (CON LCapp) (t_expr a1)) (t_expr a2)) (Is_true_conj (t_check a1) (t_check a2)). Notation "A '@' B" := (tApp A B) (at level 23, right associativity). Section Lambda_Abstraction. Variable f: term -> term. Definition nvar := newvar (t_expr (f (Bind 0))). Definition tvar := f (Var nvar). Definition tbind := ebind nvar 0 (t_expr tvar). Lemma tbind_check: tcheck tbind. Proof. unfold tbind. apply ebind_check. exact (t_check (f (Var nvar))). Qed. (* The "function body": f applied to (Bind 0). *) Definition tbody: term := mk_term tbind tbind_check. (* Higher-order lambda-abstraction. *) Definition tFun: term := mk_term (APP (CON LCabs) (ABS tbind)) tbind_check. End Lambda_Abstraction. Notation "'Fun' V , A" := (tFun (fun V => A)) (at level 20). Lemma tbind_extensional: forall f1 f2: term->term, (forall x, f1 x = f2 x) -> tbind f1 = tbind f2. Proof. intros f1 f2 H. unfold tbind; simpl. unfold tvar; simpl. unfold nvar; simpl. rewrite H. rewrite H. trivial. Qed. (* The inverse operation: given a term, build the function. *) Section Term_To_Function. Variables (e:lexp)(h:tcheck e). Variable x:term. Let xe := t_expr x. Let xh := t_check x. Let esx := bsubst e 0 xe. Lemma esx_check: tcheck esx. Proof. unfold esx. apply bsubst_check; [exact h | exact xh]. Qed. Definition tfun := mk_term esx esx_check. End Term_To_Function. Definition tapp (a:term): term -> term := tfun (t_expr a) (t_check a). (* Lemma 4 from article. *) Lemma tbody_tapp: forall a, tbody (tapp a) = a. Proof. intros [e h]; apply term_unicity; unfold tbody; unfold tapp; simpl. unfold tfun; unfold tbind; simpl. unfold nvar; simpl. rewrite bsubst_bnd. rewrite ebind_bsubst_eq. trivial. Qed. (* Definition 1 from article. *) (* "Canonical form" of a function on terms. *) Definition funt: (term -> term) -> (term -> term) := fun f => tapp (tbody f). Definition is_abst (f:term->term): Prop := forall x, f x = funt f x. Inductive eval: term -> term -> Prop := eval_Fun: forall e:term -> term, eval (Fun x, e x) (Fun x, e x) | eval_App: forall (e1 e2 v:term) (e:term->term), (eval e1 (tFun e)) -> (is_abst e) -> (eval (e e2) v) -> (eval (e1 @ e2) v). (* Lemma 5 of article. *) Lemma Fun_inj : forall e1 e2:term->term, (is_abst e1) -> (is_abst e2) -> (tFun e1)=(tFun e2) -> forall x:term, (e1 x)=(e2 x). Proof. unfold is_abst; intros e1 e2 H H0 H1 x. generalize (H x); clear H; intro H. generalize (H0 x); clear H0; intro H0. rewrite H; rewrite H0; clear H H0. unfold tFun in H1. assert (tbody e1 = tbody e2). inversion H1. unfold tbody. apply term_unicity. simpl; auto. unfold funt; rewrite H. reflexivity. Qed. (* Theorem 3 of article. *) Theorem eval_unicity : forall e v1:term, (eval e v1) -> forall v2:term, (eval e v2) -> v1=v2. Proof. intros e v1; induction 1. intros v2 H. inversion H. unfold tFun. apply mk_term_unicity. rewrite -> H1. reflexivity. intros v2 H2. inversion H2. apply IHeval2. specialize term_unicity with (1:=H3); intro H9. specialize term_unicity with (1:=H4); intro H10. subst. clear H3 H4. generalize (IHeval1 (tFun e4) H5); intro H3. generalize (Fun_inj e e4 H0 H6 H3 e2); intro H4. rewrite -> H4; auto. Qed. (* Theorem 2 in article: Induction principle for lambda-terms. *) Theorem term_induction: forall P:term->Prop, (forall v, P (Var v)) -> (forall i, P (Bind i)) -> (forall t1 t2, P t1 -> P t2 -> P (t1 @ t2)) -> (forall f, P (tbody (fun x => f x)) -> P (Fun x, f x)) -> forall t, P t. Proof. intros P Hv Hb Hap Hab t; case t. intros e c; generalize c. apply tcheck_ind with (P := fun e => forall c, P (mk_term e c)). (* Var *) intros v cv; rewrite term_unicity with (a2 := Var v). apply Hv. trivial. (* Bind *) intros i ci; rewrite term_unicity with (a2 := Bind i). apply Hb. trivial. (* Fun *) intros e1 IH c1; rewrite term_unicity with (a2 := Fun x, tfun e1 c1 x). apply Hab. rewrite term_unicity with (a2 := mk_term e1 c1). apply IH. simpl. unfold tbind; unfold nvar; unfold tfun; simpl. unfold nvar; unfold tfun; simpl. rewrite bsubst_bnd. exact (ebind_bsubst_eq e1 0). simpl. unfold tbind; unfold nvar; unfold tfun; simpl. unfold nvar; unfold tfun; simpl. rewrite bsubst_bnd. rewrite ebind_bsubst_eq. trivial. (* @ *) intros e1 e2 IH1 IH2 c'; simpl in c'. rewrite term_unicity with (a2 := (mk_term e1 (Is_true_conj_left c')) @ (mk_term e2 (Is_true_conj_right c'))). apply Hap. apply IH1. apply IH2. trivial. exact c. Qed.