adamc@158: (* Copyright (c) 2008, Adam Chlipala adamc@158: * adamc@158: * This work is licensed under a adamc@158: * Creative Commons Attribution-Noncommercial-No Derivative Works 3.0 adamc@158: * Unported License. adamc@158: * The license text is available at: adamc@158: * http://creativecommons.org/licenses/by-nc-nd/3.0/ adamc@158: *) adamc@158: adamc@158: (* begin hide *) adamc@158: Require Import Arith Eqdep String List. adamc@158: adamc@160: Require Import Axioms DepList Tactics. adamc@158: adamc@158: Set Implicit Arguments. adamc@158: (* end hide *) adamc@158: adamc@158: adamc@158: (** %\chapter{Higher-Order Abstract Syntax}% *) adamc@158: adamc@158: (** TODO: Prose for this chapter *) adamc@158: adamc@158: adamc@158: (** * Parametric Higher-Order Abstract Syntax *) adamc@158: adamc@158: Inductive type : Type := adamc@159: | Nat : type adamc@158: | Arrow : type -> type -> type. adamc@158: adamc@158: Infix "-->" := Arrow (right associativity, at level 60). adamc@158: adamc@158: Section exp. adamc@158: Variable var : type -> Type. adamc@158: adamc@158: Inductive exp : type -> Type := adamc@159: | Const' : nat -> exp Nat adamc@159: | Plus' : exp Nat -> exp Nat -> exp Nat adamc@159: adamc@158: | Var : forall t, var t -> exp t adamc@158: | App' : forall dom ran, exp (dom --> ran) -> exp dom -> exp ran adamc@158: | Abs' : forall dom ran, (var dom -> exp ran) -> exp (dom --> ran). adamc@158: End exp. adamc@158: adamc@158: Implicit Arguments Const' [var]. adamc@158: Implicit Arguments Var [var t]. adamc@158: Implicit Arguments Abs' [var dom ran]. adamc@158: adamc@158: Definition Exp t := forall var, exp var t. adamc@158: Definition Exp1 t1 t2 := forall var, var t1 -> exp var t2. adamc@158: adamc@159: Definition Const (n : nat) : Exp Nat := adamc@159: fun _ => Const' n. adamc@159: Definition Plus (E1 E2 : Exp Nat) : Exp Nat := adamc@159: fun _ => Plus' (E1 _) (E2 _). adamc@158: Definition App dom ran (F : Exp (dom --> ran)) (X : Exp dom) : Exp ran := adamc@158: fun _ => App' (F _) (X _). adamc@158: Definition Abs dom ran (B : Exp1 dom ran) : Exp (dom --> ran) := adamc@158: fun _ => Abs' (B _). adamc@158: adamc@158: Section flatten. adamc@158: Variable var : type -> Type. adamc@158: adamc@158: Fixpoint flatten t (e : exp (exp var) t) {struct e} : exp var t := adamc@158: match e in exp _ t return exp _ t with adamc@159: | Const' n => Const' n adamc@159: | Plus' e1 e2 => Plus' (flatten e1) (flatten e2) adamc@158: | Var _ e' => e' adamc@158: | App' _ _ e1 e2 => App' (flatten e1) (flatten e2) adamc@158: | Abs' _ _ e' => Abs' (fun x => flatten (e' (Var x))) adamc@158: end. adamc@158: End flatten. adamc@158: adamc@158: Definition Subst t1 t2 (E1 : Exp t1) (E2 : Exp1 t1 t2) : Exp t2 := fun _ => adamc@158: flatten (E2 _ (E1 _)). adamc@158: adamc@158: adamc@158: (** * A Type Soundness Proof *) adamc@158: adamc@158: Reserved Notation "E1 ==> E2" (no associativity, at level 90). adamc@158: adamc@158: Inductive Val : forall t, Exp t -> Prop := adamc@159: | VConst : forall n, Val (Const n) adamc@158: | VAbs : forall dom ran (B : Exp1 dom ran), Val (Abs B). adamc@158: adamc@158: Hint Constructors Val. adamc@158: adamc@158: Inductive Step : forall t, Exp t -> Exp t -> Prop := adamc@158: | Beta : forall dom ran (B : Exp1 dom ran) (X : Exp dom), adamc@160: Val X adamc@160: -> App (Abs B) X ==> Subst X B adamc@159: | AppCong1 : forall dom ran (F : Exp (dom --> ran)) (X : Exp dom) F', adamc@158: F ==> F' adamc@158: -> App F X ==> App F' X adamc@159: | AppCong2 : forall dom ran (F : Exp (dom --> ran)) (X : Exp dom) X', adamc@158: Val F adamc@158: -> X ==> X' adamc@158: -> App F X ==> App F X' adamc@158: adamc@159: | Sum : forall n1 n2, adamc@159: Plus (Const n1) (Const n2) ==> Const (n1 + n2) adamc@159: | PlusCong1 : forall E1 E2 E1', adamc@159: E1 ==> E1' adamc@159: -> Plus E1 E2 ==> Plus E1' E2 adamc@159: | PlusCong2 : forall E1 E2 E2', adamc@160: Val E1 adamc@160: -> E2 ==> E2' adamc@159: -> Plus E1 E2 ==> Plus E1 E2' adamc@159: adamc@158: where "E1 ==> E2" := (Step E1 E2). adamc@158: adamc@158: Hint Constructors Step. adamc@158: adamc@158: Inductive Closed : forall t, Exp t -> Prop := adamc@158: | CConst : forall b, adamc@158: Closed (Const b) adamc@159: | CPlus : forall E1 E2, adamc@159: Closed E1 adamc@159: -> Closed E2 adamc@159: -> Closed (Plus E1 E2) adamc@158: | CApp : forall dom ran (E1 : Exp (dom --> ran)) E2, adamc@158: Closed E1 adamc@158: -> Closed E2 adamc@158: -> Closed (App E1 E2) adamc@158: | CAbs : forall dom ran (E1 : Exp1 dom ran), adamc@158: Closed (Abs E1). adamc@158: adamc@158: Axiom closed : forall t (E : Exp t), Closed E. adamc@158: adamc@160: Ltac my_crush' := adamc@158: crush; adamc@158: repeat (match goal with adamc@158: | [ H : _ |- _ ] => generalize (inj_pairT2 _ _ _ _ _ H); clear H adamc@158: end; crush). adamc@158: adamc@160: Ltac my_crush := adamc@160: my_crush'; adamc@160: try (match goal with adamc@160: | [ H : ?F = ?G |- _ ] => adamc@160: match goal with adamc@160: | [ _ : F (fun _ => unit) = G (fun _ => unit) |- _ ] => fail 1 adamc@160: | _ => adamc@160: let H' := fresh "H'" in adamc@160: assert (H' : F (fun _ => unit) = G (fun _ => unit)); [ congruence adamc@160: | discriminate || injection H' ]; adamc@160: clear H' adamc@160: end adamc@160: end; my_crush'); adamc@160: repeat match goal with adamc@160: | [ H : ?F = ?G, H2 : ?X (fun _ => unit) = ?Y (fun _ => unit) |- _ ] => adamc@160: match X with adamc@160: | Y => fail 1 adamc@160: | _ => adamc@160: assert (X = Y); [ unfold Exp; apply ext_eq; intro var; adamc@160: let H' := fresh "H'" in adamc@160: assert (H' : F var = G var); [ congruence adamc@160: | match type of H' with adamc@160: | ?X = ?Y => adamc@160: let X := eval hnf in X in adamc@160: let Y := eval hnf in Y in adamc@160: change (X = Y) in H' adamc@160: end; injection H'; clear H'; my_crush' ] adamc@160: | my_crush'; clear H2 ] adamc@160: end adamc@160: end. adamc@160: adamc@158: Lemma progress' : forall t (E : Exp t), adamc@158: Closed E adamc@158: -> Val E \/ exists E', E ==> E'. adamc@158: induction 1; crush; adamc@159: repeat match goal with adamc@159: | [ H : Val _ |- _ ] => inversion H; []; clear H; my_crush adamc@159: end; eauto. adamc@158: Qed. adamc@158: adamc@158: Theorem progress : forall t (E : Exp t), adamc@158: Val E \/ exists E', E ==> E'. adamc@158: intros; apply progress'; apply closed. adamc@158: Qed. adamc@158: adamc@160: adamc@160: (** * Big-Step Semantics *) adamc@160: adamc@160: Reserved Notation "E1 ===> E2" (no associativity, at level 90). adamc@160: adamc@160: Inductive BigStep : forall t, Exp t -> Exp t -> Prop := adamc@160: | SConst : forall n, adamc@160: Const n ===> Const n adamc@160: | SPlus : forall E1 E2 n1 n2, adamc@160: E1 ===> Const n1 adamc@160: -> E2 ===> Const n2 adamc@160: -> Plus E1 E2 ===> Const (n1 + n2) adamc@160: adamc@160: | SApp : forall dom ran (E1 : Exp (dom --> ran)) E2 B V2 V, adamc@160: E1 ===> Abs B adamc@160: -> E2 ===> V2 adamc@160: -> Subst V2 B ===> V adamc@160: -> App E1 E2 ===> V adamc@160: | SAbs : forall dom ran (B : Exp1 dom ran), adamc@160: Abs B ===> Abs B adamc@160: adamc@160: where "E1 ===> E2" := (BigStep E1 E2). adamc@160: adamc@160: Hint Constructors BigStep. adamc@160: adamc@160: Reserved Notation "E1 ==>* E2" (no associativity, at level 90). adamc@160: adamc@160: Inductive MultiStep : forall t, Exp t -> Exp t -> Prop := adamc@160: | Done : forall t (E : Exp t), E ==>* E adamc@160: | OneStep : forall t (E E' E'' : Exp t), adamc@160: E ==> E' adamc@160: -> E' ==>* E'' adamc@160: -> E ==>* E'' adamc@160: adamc@160: where "E1 ==>* E2" := (MultiStep E1 E2). adamc@160: adamc@160: Hint Constructors MultiStep. adamc@160: adamc@160: Theorem MultiStep_trans : forall t (E1 E2 E3 : Exp t), adamc@160: E1 ==>* E2 adamc@160: -> E2 ==>* E3 adamc@160: -> E1 ==>* E3. adamc@160: induction 1; eauto. adamc@160: Qed. adamc@160: adamc@160: Hint Resolve MultiStep_trans. adamc@160: adamc@160: Theorem Big_Val : forall t (E V : Exp t), adamc@160: E ===> V adamc@160: -> Val V. adamc@160: induction 1; crush. adamc@160: Qed. adamc@160: adamc@160: Theorem Val_Big : forall t (V : Exp t), adamc@160: Val V adamc@160: -> V ===> V. adamc@160: destruct 1; crush. adamc@160: Qed. adamc@160: adamc@160: Hint Resolve Big_Val Val_Big. adamc@160: adamc@160: Ltac uiper := adamc@160: repeat match goal with adamc@160: | [ pf : _ = _ |- _ ] => adamc@160: generalize pf; subst; intro; adamc@160: rewrite (UIP_refl _ _ pf); simpl; adamc@160: repeat match goal with adamc@160: | [ H : forall pf : ?X = ?X, _ |- _ ] => adamc@160: generalize (H (refl_equal _)); clear H; intro H adamc@160: end adamc@160: end. adamc@160: adamc@160: Lemma Multi_PlusCong1' : forall E2 t (pf : t = Nat) (E1 E1' : Exp t), adamc@160: E1 ==>* E1' adamc@160: -> Plus (match pf with refl_equal => E1 end) E2 adamc@160: ==>* Plus (match pf with refl_equal => E1' end) E2. adamc@160: induction 1; crush; uiper; eauto. adamc@160: Qed. adamc@160: adamc@160: Lemma Multi_PlusCong1 : forall E1 E2 E1', adamc@160: E1 ==>* E1' adamc@160: -> Plus E1 E2 ==>* Plus E1' E2. adamc@160: intros; generalize (Multi_PlusCong1' E2 (refl_equal _)); auto. adamc@160: Qed. adamc@160: adamc@160: Lemma Multi_PlusCong2' : forall E1 (_ : Val E1) t (pf : t = Nat) (E2 E2' : Exp t), adamc@160: E2 ==>* E2' adamc@160: -> Plus E1 (match pf with refl_equal => E2 end) adamc@160: ==>* Plus E1 (match pf with refl_equal => E2' end). adamc@160: induction 2; crush; uiper; eauto. adamc@160: Qed. adamc@160: adamc@160: Lemma Multi_PlusCong2 : forall E1 E2 E2', adamc@160: Val E1 adamc@160: -> E2 ==>* E2' adamc@160: -> Plus E1 E2 ==>* Plus E1 E2'. adamc@160: intros E1 E2 E2' H; generalize (Multi_PlusCong2' H (refl_equal _)); auto. adamc@160: Qed. adamc@160: adamc@160: Lemma Multi_AppCong1' : forall dom ran E2 t (pf : t = dom --> ran) (E1 E1' : Exp t), adamc@160: E1 ==>* E1' adamc@160: -> App (match pf in _ = t' return Exp t' with refl_equal => E1 end) E2 adamc@160: ==>* App (match pf in _ = t' return Exp t' with refl_equal => E1' end) E2. adamc@160: induction 1; crush; uiper; eauto. adamc@160: Qed. adamc@160: adamc@160: Lemma Multi_AppCong1 : forall dom ran (E1 : Exp (dom --> ran)) E2 E1', adamc@160: E1 ==>* E1' adamc@160: -> App E1 E2 ==>* App E1' E2. adamc@160: intros; generalize (Multi_AppCong1' (ran := ran) E2 (refl_equal _)); auto. adamc@160: Qed. adamc@160: adamc@160: Lemma Multi_AppCong2 : forall dom ran (E1 : Exp (dom --> ran)) E2 E2', adamc@160: Val E1 adamc@160: -> E2 ==>* E2' adamc@160: -> App E1 E2 ==>* App E1 E2'. adamc@160: induction 2; crush; eauto. adamc@160: Qed. adamc@160: adamc@160: Hint Resolve Multi_PlusCong1 Multi_PlusCong2 Multi_AppCong1 Multi_AppCong2. adamc@160: adamc@160: Theorem Big_Multi : forall t (E V : Exp t), adamc@160: E ===> V adamc@160: -> E ==>* V. adamc@160: induction 1; crush; eauto 8. adamc@160: Qed. adamc@160: adamc@160: Lemma Big_Val' : forall t (V1 V2 : Exp t), adamc@160: Val V2 adamc@160: -> V1 = V2 adamc@160: -> V1 ===> V2. adamc@160: crush. adamc@160: Qed. adamc@160: adamc@160: Hint Resolve Big_Val'. adamc@160: adamc@160: Lemma Multi_Big' : forall t (E E' : Exp t), adamc@160: E ==> E' adamc@160: -> forall E'', E' ===> E'' adamc@160: -> E ===> E''. adamc@160: induction 1; crush; eauto; adamc@160: match goal with adamc@160: | [ H : _ ===> _ |- _ ] => inversion H; my_crush; eauto adamc@160: end. adamc@160: Qed. adamc@160: adamc@160: Hint Resolve Multi_Big'. adamc@160: adamc@160: Theorem Multi_Big : forall t (E V : Exp t), adamc@160: E ==>* V adamc@160: -> Val V adamc@160: -> E ===> V. adamc@160: induction 1; crush; eauto. adamc@160: Qed. adamc@160: adamc@160: adamc@160: (** * Constant folding *) adamc@160: adamc@160: Section cfold. adamc@160: Variable var : type -> Type. adamc@160: adamc@160: Fixpoint cfold t (e : exp var t) {struct e} : exp var t := adamc@160: match e in exp _ t return exp _ t with adamc@160: | Const' n => Const' n adamc@160: | Plus' e1 e2 => adamc@160: let e1' := cfold e1 in adamc@160: let e2' := cfold e2 in adamc@160: match e1', e2' with adamc@160: | Const' n1, Const' n2 => Const' (n1 + n2) adamc@160: | _, _ => Plus' e1' e2' adamc@160: end adamc@160: adamc@160: | Var _ x => Var x adamc@160: | App' _ _ e1 e2 => App' (cfold e1) (cfold e2) adamc@160: | Abs' _ _ e' => Abs' (fun x => cfold (e' x)) adamc@160: end. adamc@160: End cfold. adamc@160: adamc@160: Definition Cfold t (E : Exp t) : Exp t := fun _ => cfold (E _). adamc@160: adamc@160: adamc@160: Definition ExpN (G : list type) (t : type) := forall var, hlist var G -> exp var t. adamc@160: adamc@160: Definition ConstN G (n : nat) : ExpN G Nat := adamc@160: fun _ _ => Const' n. adamc@160: Definition PlusN G (E1 E2 : ExpN G Nat) : ExpN G Nat := adamc@160: fun _ s => Plus' (E1 _ s) (E2 _ s). adamc@160: Definition AppN G dom ran (F : ExpN G (dom --> ran)) (X : ExpN G dom) : ExpN G ran := adamc@160: fun _ s => App' (F _ s) (X _ s). adamc@160: Definition AbsN G dom ran (B : ExpN (dom :: G) ran) : ExpN G (dom --> ran) := adamc@160: fun _ s => Abs' (fun x => B _ (x ::: s)).