Mercurial > cpdt > repo
view src/Hoas.v @ 163:ba306bf9ec80
Feeling stuck with Hoas
author | Adam Chlipala <adamc@hcoop.net> |
---|---|
date | Tue, 04 Nov 2008 16:45:50 -0500 |
parents | df02642f93b8 |
children | 391ccedd0568 |
line wrap: on
line source
(* Copyright (c) 2008, Adam Chlipala * * This work is licensed under a * Creative Commons Attribution-Noncommercial-No Derivative Works 3.0 * Unported License. * The license text is available at: * http://creativecommons.org/licenses/by-nc-nd/3.0/ *) (* begin hide *) Require Import Arith Eqdep String List. Require Import Axioms DepList Tactics. Set Implicit Arguments. (* end hide *) (** %\chapter{Higher-Order Abstract Syntax}% *) (** TODO: Prose for this chapter *) (** * Parametric Higher-Order Abstract Syntax *) Inductive type : Type := | Nat : type | Arrow : type -> type -> type. Infix "-->" := Arrow (right associativity, at level 60). Section exp. Variable var : type -> Type. Inductive exp : type -> Type := | Const' : nat -> exp Nat | Plus' : exp Nat -> exp Nat -> exp Nat | Var : forall t, var t -> exp t | App' : forall dom ran, exp (dom --> ran) -> exp dom -> exp ran | Abs' : forall dom ran, (var dom -> exp ran) -> exp (dom --> ran). End exp. Implicit Arguments Const' [var]. Implicit Arguments Var [var t]. Implicit Arguments Abs' [var dom ran]. Definition Exp t := forall var, exp var t. Definition Exp1 t1 t2 := forall var, var t1 -> exp var t2. Definition Const (n : nat) : Exp Nat := fun _ => Const' n. Definition Plus (E1 E2 : Exp Nat) : Exp Nat := fun _ => Plus' (E1 _) (E2 _). Definition App dom ran (F : Exp (dom --> ran)) (X : Exp dom) : Exp ran := fun _ => App' (F _) (X _). Definition Abs dom ran (B : Exp1 dom ran) : Exp (dom --> ran) := fun _ => Abs' (B _). Section flatten. Variable var : type -> Type. Fixpoint flatten t (e : exp (exp var) t) {struct e} : exp var t := match e in exp _ t return exp _ t with | Const' n => Const' n | Plus' e1 e2 => Plus' (flatten e1) (flatten e2) | Var _ e' => e' | App' _ _ e1 e2 => App' (flatten e1) (flatten e2) | Abs' _ _ e' => Abs' (fun x => flatten (e' (Var x))) end. End flatten. Definition Subst t1 t2 (E1 : Exp t1) (E2 : Exp1 t1 t2) : Exp t2 := fun _ => flatten (E2 _ (E1 _)). (** * A Type Soundness Proof *) Reserved Notation "E1 ==> E2" (no associativity, at level 90). Inductive Val : forall t, Exp t -> Prop := | VConst : forall n, Val (Const n) | VAbs : forall dom ran (B : Exp1 dom ran), Val (Abs B). Hint Constructors Val. Inductive Ctx : type -> type -> Type := | AppCong1 : forall (dom ran : type), Exp dom -> Ctx (dom --> ran) ran | AppCong2 : forall (dom ran : type), Exp (dom --> ran) -> Ctx dom ran | PlusCong1 : Exp Nat -> Ctx Nat Nat | PlusCong2 : Exp Nat -> Ctx Nat Nat. Inductive isCtx : forall t1 t2, Ctx t1 t2 -> Prop := | IsApp1 : forall dom ran (X : Exp dom), isCtx (AppCong1 ran X) | IsApp2 : forall dom ran (F : Exp (dom --> ran)), Val F -> isCtx (AppCong2 F) | IsPlus1 : forall E2, isCtx (PlusCong1 E2) | IsPlus2 : forall E1, Val E1 -> isCtx (PlusCong2 E1). Definition plug t1 t2 (C : Ctx t1 t2) : Exp t1 -> Exp t2 := match C in Ctx t1 t2 return Exp t1 -> Exp t2 with | AppCong1 _ _ X => fun F => App F X | AppCong2 _ _ F => fun X => App F X | PlusCong1 E2 => fun E1 => Plus E1 E2 | PlusCong2 E1 => fun E2 => Plus E1 E2 end. Infix "@" := plug (no associativity, at level 60). Inductive Step : forall t, Exp t -> Exp t -> Prop := | Beta : forall dom ran (B : Exp1 dom ran) (X : Exp dom), Val X -> App (Abs B) X ==> Subst X B | Sum : forall n1 n2, Plus (Const n1) (Const n2) ==> Const (n1 + n2) | Cong : forall t t' (C : Ctx t t') E E' E1, isCtx C -> E1 = C @ E -> E ==> E' -> E1 ==> C @ E' where "E1 ==> E2" := (Step E1 E2). Hint Constructors isCtx Step. Inductive Closed : forall t, Exp t -> Prop := | CConst : forall b, Closed (Const b) | CPlus : forall E1 E2, Closed E1 -> Closed E2 -> Closed (Plus E1 E2) | CApp : forall dom ran (E1 : Exp (dom --> ran)) E2, Closed E1 -> Closed E2 -> Closed (App E1 E2) | CAbs : forall dom ran (E1 : Exp1 dom ran), Closed (Abs E1). Axiom closed : forall t (E : Exp t), Closed E. Ltac my_subst := repeat match goal with | [ x : type |- _ ] => subst x end. Ltac my_crush' := crush; my_subst; repeat (match goal with | [ H : _ |- _ ] => generalize (inj_pairT2 _ _ _ _ _ H); clear H end; crush; my_subst). Ltac equate_conj F G := match constr:(F, G) with | (_ ?x1, _ ?x2) => constr:(x1 = x2) | (_ ?x1 ?y1, _ ?x2 ?y2) => constr:(x1 = x2 /\ y1 = y2) | (_ ?x1 ?y1 ?z1, _ ?x2 ?y2 ?z2) => constr:(x1 = x2 /\ y1 = y2 /\ z1 = z2) | (_ ?x1 ?y1 ?z1 ?u1, _ ?x2 ?y2 ?z2 ?u2) => constr:(x1 = x2 /\ y1 = y2 /\ z1 = z2 /\ u1 = u2) | (_ ?x1 ?y1 ?z1 ?u1 ?v1, _ ?x2 ?y2 ?z2 ?u2 ?v2) => constr:(x1 = x2 /\ y1 = y2 /\ z1 = z2 /\ u1 = u2 /\ v1 = v2) end. Ltac my_crush := my_crush'; repeat (match goal with | [ H : ?F = ?G |- _ ] => (let H' := fresh "H'" in assert (H' : F (fun _ => unit) = G (fun _ => unit)); [ congruence | discriminate || injection H'; clear H' ]; my_crush'; repeat match goal with | [ H : context[fun _ => unit] |- _ ] => clear H end; match type of H with | ?F = ?G => let ec := equate_conj F G in let var := fresh "var" in assert ec; [ intuition; unfold Exp; apply ext_eq; intro var; assert (H' : F var = G var); try congruence; match type of H' with | ?X = ?Y => let X := eval hnf in X in let Y := eval hnf in Y in change (X = Y) in H' end; injection H'; my_crush'; tauto | intuition; subst ] end); clear H end; my_crush'); my_crush'. Hint Extern 1 (_ = _ @ _) => simpl. Lemma progress' : forall t (E : Exp t), Closed E -> Val E \/ exists E', E ==> E'. induction 1; crush; repeat match goal with | [ H : Val _ |- _ ] => inversion H; []; clear H; my_crush end; eauto 6. Qed. Theorem progress : forall t (E : Exp t), Val E \/ exists E', E ==> E'. intros; apply progress'; apply closed. Qed. (** * Big-Step Semantics *) Reserved Notation "E1 ===> E2" (no associativity, at level 90). Inductive BigStep : forall t, Exp t -> Exp t -> Prop := | SConst : forall n, Const n ===> Const n | SPlus : forall E1 E2 n1 n2, E1 ===> Const n1 -> E2 ===> Const n2 -> Plus E1 E2 ===> Const (n1 + n2) | SApp : forall dom ran (E1 : Exp (dom --> ran)) E2 B V2 V, E1 ===> Abs B -> E2 ===> V2 -> Subst V2 B ===> V -> App E1 E2 ===> V | SAbs : forall dom ran (B : Exp1 dom ran), Abs B ===> Abs B where "E1 ===> E2" := (BigStep E1 E2). Hint Constructors BigStep. Reserved Notation "E1 ==>* E2" (no associativity, at level 90). Inductive MultiStep : forall t, Exp t -> Exp t -> Prop := | Done : forall t (E : Exp t), E ==>* E | OneStep : forall t (E E' E'' : Exp t), E ==> E' -> E' ==>* E'' -> E ==>* E'' where "E1 ==>* E2" := (MultiStep E1 E2). Hint Constructors MultiStep. Theorem MultiStep_trans : forall t (E1 E2 E3 : Exp t), E1 ==>* E2 -> E2 ==>* E3 -> E1 ==>* E3. induction 1; eauto. Qed. Theorem Big_Val : forall t (E V : Exp t), E ===> V -> Val V. induction 1; crush. Qed. Theorem Val_Big : forall t (V : Exp t), Val V -> V ===> V. destruct 1; crush. Qed. Hint Resolve Big_Val Val_Big. Lemma Multi_Cong : forall t t' (C : Ctx t t'), isCtx C -> forall E E', E ==>* E' -> C @ E ==>* C @ E'. induction 2; crush; eauto. Qed. Lemma Multi_Cong' : forall t t' (C : Ctx t t') E1 E2 E E', isCtx C -> E1 = C @ E -> E2 = C @ E' -> E ==>* E' -> E1 ==>* E2. crush; apply Multi_Cong; auto. Qed. Hint Resolve Multi_Cong'. Ltac mtrans E := match goal with | [ |- E ==>* _ ] => fail 1 | _ => apply MultiStep_trans with E; [ solve [ eauto ] | eauto ] end. Theorem Big_Multi : forall t (E V : Exp t), E ===> V -> E ==>* V. induction 1; crush; eauto; repeat match goal with | [ n1 : _, E2 : _ |- _ ] => mtrans (Plus (Const n1) E2) | [ n1 : _, n2 : _ |- _ ] => mtrans (Plus (Const n1) (Const n2)) | [ B : _, E2 : _ |- _ ] => mtrans (App (Abs B) E2) end. Qed. Lemma Big_Val' : forall t (V1 V2 : Exp t), Val V2 -> V1 = V2 -> V1 ===> V2. crush. Qed. Hint Resolve Big_Val'. Lemma Multi_Big' : forall t (E E' : Exp t), E ==> E' -> forall E'', E' ===> E'' -> E ===> E''. induction 1; crush; eauto; match goal with | [ H : _ ===> _ |- _ ] => inversion H; my_crush; eauto end; match goal with | [ H : isCtx _ |- _ ] => inversion H; my_crush; eauto end. Qed. Hint Resolve Multi_Big'. Theorem Multi_Big : forall t (E V : Exp t), E ==>* V -> Val V -> E ===> V. induction 1; crush; eauto. Qed. (** * Constant folding *) Section cfold. Variable var : type -> Type. Fixpoint cfold t (e : exp var t) {struct e} : exp var t := match e in exp _ t return exp _ t with | Const' n => Const' n | Plus' e1 e2 => let e1' := cfold e1 in let e2' := cfold e2 in match e1', e2' with | Const' n1, Const' n2 => Const' (n1 + n2) | _, _ => Plus' e1' e2' end | Var _ x => Var x | App' _ _ e1 e2 => App' (cfold e1) (cfold e2) | Abs' _ _ e' => Abs' (fun x => cfold (e' x)) end. End cfold. Definition Cfold t (E : Exp t) : Exp t := fun _ => cfold (E _). Definition Cfold1 t1 t2 (E : Exp1 t1 t2) : Exp1 t1 t2 := fun _ x => cfold (E _ x). Lemma fold_Cfold : forall t (E : Exp t), (fun _ => cfold (E _)) = Cfold E. reflexivity. Qed. Hint Rewrite fold_Cfold : fold. Lemma fold_Cfold1 : forall t1 t2 (E : Exp1 t1 t2), (fun _ x => cfold (E _ x)) = Cfold1 E. reflexivity. Qed. Lemma fold_Subst_Cfold1 : forall t1 t2 (E : Exp1 t1 t2) (V : Exp t1), (fun _ => flatten (cfold (E _ (V _)))) = Subst V (Cfold1 E). reflexivity. Qed. Axiom cheat : forall T, T. Lemma fold_Const : forall n, (fun _ => Const' n) = Const n. reflexivity. Qed. Lemma fold_Plus : forall (E1 E2 : Exp _), (fun _ => Plus' (E1 _) (E2 _)) = Plus E1 E2. reflexivity. Qed. Lemma fold_App : forall dom ran (F : Exp (dom --> ran)) (X : Exp dom), (fun _ => App' (F _) (X _)) = App F X. reflexivity. Qed. Lemma fold_Abs : forall dom ran (B : Exp1 dom ran), (fun _ => Abs' (B _)) = Abs B. reflexivity. Qed. Hint Rewrite fold_Const fold_Plus fold_App fold_Abs : fold. Lemma fold_Subst : forall t1 t2 (E1 : Exp1 t1 t2) (V : Exp t1), (fun _ => flatten (E1 _ (V _))) = Subst V E1. reflexivity. Qed. Hint Rewrite fold_Subst : fold. Definition ExpN (G : list type) (t : type) := forall var, hlist var G -> exp var t. Definition ConstN G (n : nat) : ExpN G Nat := fun _ _ => Const' n. Definition VarN G t (m : member t G) : ExpN G t := fun _ s => Var (hget s m). Definition PlusN G (E1 E2 : ExpN G Nat) : ExpN G Nat := fun _ s => Plus' (E1 _ s) (E2 _ s). Definition AppN G dom ran (F : ExpN G (dom --> ran)) (X : ExpN G dom) : ExpN G ran := fun _ s => App' (F _ s) (X _ s). Definition AbsN G dom ran (B : ExpN (dom :: G) ran) : ExpN G (dom --> ran) := fun _ s => Abs' (fun x => B _ (x ::: s)). Inductive ClosedN : forall G t, ExpN G t -> Prop := | CConstN : forall G b, ClosedN (ConstN G b) | CPlusN : forall G (E1 E2 : ExpN G _), ClosedN E1 -> ClosedN E2 -> ClosedN (PlusN E1 E2) | CAppN : forall G dom ran (E1 : ExpN G (dom --> ran)) E2, ClosedN E1 -> ClosedN E2 -> ClosedN (AppN E1 E2) | CAbsN : forall G dom ran (E1 : ExpN (dom :: G) ran), ClosedN E1 -> ClosedN (AbsN E1). Axiom closedN : forall G t (E : ExpN G t), ClosedN E. Hint Resolve closedN. Section Closed1. Variable xt : type. Definition Const1 (n : nat) : Exp1 xt Nat := fun _ _ => Const' n. Definition Var1 : Exp1 xt xt := fun _ x => Var x. Definition Plus1 (E1 E2 : Exp1 xt Nat) : Exp1 xt Nat := fun _ s => Plus' (E1 _ s) (E2 _ s). Definition App1 dom ran (F : Exp1 xt (dom --> ran)) (X : Exp1 xt dom) : Exp1 xt ran := fun _ s => App' (F _ s) (X _ s). Definition Abs1 dom ran (B : forall var, var dom -> Exp1 xt ran) : Exp1 xt (dom --> ran) := fun _ s => Abs' (fun x => B _ x _ s). Inductive Closed1 : forall t, Exp1 xt t -> Prop := | CConst1 : forall b, Closed1 (Const1 b) | CPlus1 : forall E1 E2, Closed1 E1 -> Closed1 E2 -> Closed1 (Plus1 E1 E2) | CApp1 : forall dom ran (E1 : Exp1 _ (dom --> ran)) E2, Closed1 E1 -> Closed1 E2 -> Closed1 (App1 E1 E2) | CAbs1 : forall dom ran (E1 : forall var, var dom -> Exp1 _ ran), Closed1 (Abs1 E1). Axiom closed1 : forall t (E : Exp1 xt t), Closed1 E. End Closed1. Hint Resolve closed1. Definition CfoldN G t (E : ExpN G t) : ExpN G t := fun _ s => cfold (E _ s). Theorem fold_CfoldN : forall G t (E : ExpN G t), (fun _ s => cfold (E _ s)) = CfoldN E. reflexivity. Qed. Definition SubstN t1 G t2 (E1 : ExpN G t1) (E2 : ExpN (G ++ t1 :: nil) t2) : ExpN G t2 := fun _ s => flatten (E2 _ (hmap (@Var _) s +++ E1 _ s ::: hnil)). Lemma fold_SubstN : forall t1 G t2 (E1 : ExpN G t1) (E2 : ExpN (G ++ t1 :: nil) t2), (fun _ s => flatten (E2 _ (hmap (@Var _) s +++ E1 _ s ::: hnil))) = SubstN E1 E2. reflexivity. Qed. Hint Rewrite fold_CfoldN fold_SubstN : fold. Ltac ssimp := unfold Subst, Cfold, CfoldN, SubstN in *; simpl in *; autorewrite with fold in *; repeat match goal with | [ xt : type |- _ ] => rewrite (@fold_Subst xt) in * end; autorewrite with fold in *. Ltac uiper := repeat match goal with | [ H : _ = _ |- _ ] => generalize H; subst; intro H; rewrite (UIP_refl _ _ H) end. Section eq_arg. Variable A : Type. Variable B : A -> Type. Variable x : A. Variables f g : forall x, B x. Hypothesis Heq : f = g. Theorem eq_arg : f x = g x. congruence. Qed. End eq_arg. Implicit Arguments eq_arg [A B f g]. (*Lemma Cfold_Subst_comm : forall G t (E : ExpN G t), ClosedN E -> forall t1 G' (pf : G = G' ++ t1 :: nil) V, CfoldN (SubstN V (match pf in _ = G return ExpN G _ with refl_equal => E end)) = SubstN (CfoldN V) (CfoldN (match pf in _ = G return ExpN G _ with refl_equal => E end)). induction 1; my_crush; uiper; ssimp; crush; unfold ExpN; do 2 ext_eq. generalize (eq_arg x0 (eq_arg x (IHClosedN1 _ _ (refl_equal _) V))). generalize (eq_arg x0 (eq_arg x (IHClosedN2 _ _ (refl_equal _) V))). crush. match goal with | [ |- _ = flatten (match ?E with | Const' _ => _ | Plus' _ _ => _ | Var _ _ => _ | App' _ _ _ _ => _ | Abs' _ _ _ => _ end) ] => dep_destruct E end; crush. match goal with | [ |- _ = flatten (match ?E with | Const' _ => _ | Plus' _ _ => _ | Var _ _ => _ | App' _ _ _ _ => _ | Abs' _ _ _ => _ end) ] => dep_destruct E end; crush. match goal with | [ |- match ?E with | Const' _ => _ | Plus' _ _ => _ | Var _ _ => _ | App' _ _ _ _ => _ | Abs' _ _ _ => _ end = _ ] => dep_destruct E end; crush. rewrite <- H2. dep_destruct e. intro apply cheat. unfold ExpN; do 2 ext_eq. generalize (eq_arg x0 (eq_arg x (IHClosedN1 _ _ (refl_equal _) V))). generalize (eq_arg x0 (eq_arg x (IHClosedN2 _ _ (refl_equal _) V))). congruence. unfold ExpN; do 2 ext_eq. f_equal. ext_eq. exact (eq_arg (x1 ::: x0) (eq_arg x (IHClosedN _ (dom :: G') (refl_equal _) (fun _ s => V _ (snd s))))). Qed.*) Lemma Cfold_Subst' : forall t (E V' : Exp t), E ===> V' -> forall G xt (V : ExpN G xt) B, E = SubstN V B -> ClosedN B -> Subst (Cfold V) (Cfold1 B) ===> Cfold V'. induction 1; inversion 2; my_crush; ssimp. auto. apply cheat. my_crush. econstructor. instantiate (1 := Cfold1 B). unfold Subst, Cfold1 in *; eauto. unfold Subst, Cfold1 in *; eauto. unfold Subst, Cfold; eauto. my_crush; ssimp. Lemma Cfold_Subst' : forall t (B : Exp1 xt t), Closed1 B -> forall V', Subst V B ===> V' -> Subst (Cfold V) (Cfold1 B) ===> Cfold V'. induction 1; my_crush; ssimp. inversion H; my_crush. apply cheat. inversion H1; my_crush. econstructor. instantiate (1 := Cfold1 B). eauto. change (Abs (Cfold1 B)) with (Cfold (Abs B)). auto. eauto. eauto. apply IHClosed1_1. eauto. match goal with | [ (*H : ?F = ?G,*) H2 : ?X (fun _ => unit) = ?Y _ _ _ _ (fun _ => unit) |- _ ] => idtac(*match X with | Y => fail 1 | _ => idtac(*assert (X = Y); [ unfold Exp; apply ext_eq; intro var; let H' := fresh "H'" in assert (H' : F var = G var); [ congruence | match type of H' with | ?X = ?Y => let X := eval hnf in X in let Y := eval hnf in Y in change (X = Y) in H' end; injection H'; clear H'; my_crush' ] | my_crush'; clear H2 ]*) end*) end. clear H5 H3. my_crush. unfold Subst in *; simpl in *; autorewrite with fold in *. Check fold_Subst. repeat rewrite (@fold_Subst t1) in *. simp (Subst (t2 := Nat) V). induction 1; my_crush. End Exp1. Axiom closed1 : forall t1 t2 (E : Exp1 t1 t2), Closed1 E. Lemma Cfold_Subst' : forall t1 (V : Exp t1) t2 (B : Exp1 t1 t2), Closed1 B -> forall V', Subst V B ===> V' -> Subst (Cfold V) (Cfold1 B) ===> Cfold V'. induction 1; my_crush. unfold Subst in *; simpl in *; autorewrite with fold in *. inversion H; my_crush. unfold Subst in *; simpl in *; autorewrite with fold in *. Check fold_Subst. repeat rewrite (@fold_Subst t1) in *. simp (Subst (t2 := Nat) V). induction 1; my_crush. Theorem Cfold_Subst : forall t1 t2 (V : Exp t1) B (V' : Exp t2), Subst V B ===> V' -> Subst (Cfold V) (Cfold1 B) ===> Cfold V'. Theorem Cfold_correct : forall t (E V : Exp t), E ===> V -> Cfold E ===> Cfold V. induction 1; unfold Cfold in *; crush; simp; auto. simp. simp. apply cheat. simp. econstructor; eauto. match goal with | [ |- ?E ===> ?V ] => try simp1 ltac:(fun E' => change (E' ===> V)); try match goal with | [ |- ?E' ===> _ ] => simp1 ltac:(fun V' => change (E' ===> V')) end | [ H : ?E ===> ?V |- _ ] => try simp1 ltac:(fun E' => change (E' ===> V) in H); try match type of H with | ?E' ===> _ => simp1 ltac:(fun V' => change (E' ===> V') in H) end end. simp. let H := IHBigStep1 in match type of H with | ?E ===> ?V => try simp1 ltac:(fun E' => change (E' ===> V) in H); try match type of H with | ?E' ===> _ => simp1 ltac:(fun V' => change (E' ===> V') in H) end end. try simp1 ltac:(fun E' => change (E' ===> V) in H) end. simp. try simp1 ltac:(fun E' => change (fun H : type -> Type => cfold (E1 H)) with E' in IHBigStep1). try simp1 ltac:(fun V' => change (fun H : type -> Type => Abs' (dom:=dom) (fun x : H dom => cfold (B H x))) with V' in IHBigStep1). simp1 ltac:(fun E => change ((fun H : type -> Type => cfold (E1 H)) ===> E) in IHBigStep1). change ((fun H : type -> Type => cfold (E1 H)) ===> Abs (fun _ x => cfold (B _ x))) in IHBigStep1. (fun H : type -> Type => Abs' (dom:=dom) (fun x : H dom => cfold (B H x))) fold Cfold. Definition ExpN (G : list type) (t : type) := forall var, hlist var G -> exp var t. Definition ConstN G (n : nat) : ExpN G Nat := fun _ _ => Const' n. Definition PlusN G (E1 E2 : ExpN G Nat) : ExpN G Nat := fun _ s => Plus' (E1 _ s) (E2 _ s). Definition AppN G dom ran (F : ExpN G (dom --> ran)) (X : ExpN G dom) : ExpN G ran := fun _ s => App' (F _ s) (X _ s). Definition AbsN G dom ran (B : ExpN (dom :: G) ran) : ExpN G (dom --> ran) := fun _ s => Abs' (fun x => B _ (x ::: s)).