import implementation of Fsub from the Coq tutorial of UPenn
taken from 'https://www.cis.upenn.edu/~plclub/popl08-tutorial/code/index.html'
This commit is contained in:
parent
44d8d401d8
commit
05c137c489
13 changed files with 4847 additions and 0 deletions
109
coq-Fsub/AdditionalTactics.v
Normal file
109
coq-Fsub/AdditionalTactics.v
Normal file
|
@ -0,0 +1,109 @@
|
||||||
|
(** A library of additional tactics. *)
|
||||||
|
|
||||||
|
Require Export String.
|
||||||
|
Open Scope string_scope.
|
||||||
|
|
||||||
|
|
||||||
|
(* *********************************************************************** *)
|
||||||
|
(** * Extensions of the standard library *)
|
||||||
|
|
||||||
|
(** "[remember c as x in |-]" replaces the term [c] by the identifier
|
||||||
|
[x] in the conclusion of the current goal and introduces the
|
||||||
|
hypothesis [x=c] into the context. This tactic differs from a
|
||||||
|
similar one in the standard library in that the replacmement is
|
||||||
|
made only in the conclusion of the goal; the context is left
|
||||||
|
unchanged. *)
|
||||||
|
|
||||||
|
Tactic Notation "remember" constr(c) "as" ident(x) "in" "|-" :=
|
||||||
|
let x := fresh x in
|
||||||
|
let H := fresh "Heq" x in
|
||||||
|
(set (x := c); assert (H : x = c) by reflexivity; clearbody x).
|
||||||
|
|
||||||
|
(** "[unsimpl E]" replaces all occurence of [X] by [E], where [X] is
|
||||||
|
the result that tactic [simpl] would give when used to evaluate
|
||||||
|
[E]. *)
|
||||||
|
|
||||||
|
Tactic Notation "unsimpl" constr(E) :=
|
||||||
|
let F := (eval simpl in E) in change F with E.
|
||||||
|
|
||||||
|
(** The following tactic calls the [apply] tactic with the first
|
||||||
|
hypothesis that succeeds, "first" meaning the hypothesis that
|
||||||
|
comes earlist in the context (i.e., higher up in the list). *)
|
||||||
|
|
||||||
|
Ltac apply_first_hyp :=
|
||||||
|
match reverse goal with
|
||||||
|
| H : _ |- _ => apply H
|
||||||
|
end.
|
||||||
|
|
||||||
|
|
||||||
|
(* *********************************************************************** *)
|
||||||
|
(** * Variations on [auto] *)
|
||||||
|
|
||||||
|
(** The [auto*] and [eauto*] tactics are intended to be "stronger"
|
||||||
|
versions of the [auto] and [eauto] tactics. Similar to [auto] and
|
||||||
|
[eauto], they each take an optional "depth" argument. Note that
|
||||||
|
if we declare these tactics using a single string, e.g., "auto*",
|
||||||
|
then the resulting tactics are unusable since they fail to
|
||||||
|
parse. *)
|
||||||
|
|
||||||
|
Tactic Notation "auto" "*" :=
|
||||||
|
try solve [ congruence | auto | intuition auto ].
|
||||||
|
|
||||||
|
Tactic Notation "auto" "*" integer(n) :=
|
||||||
|
try solve [ congruence | auto n | intuition (auto n) ].
|
||||||
|
|
||||||
|
Tactic Notation "eauto" "*" :=
|
||||||
|
try solve [ congruence | eauto | intuition eauto ].
|
||||||
|
|
||||||
|
Tactic Notation "eauto" "*" integer(n) :=
|
||||||
|
try solve [ congruence | eauto n | intuition (eauto n) ].
|
||||||
|
|
||||||
|
|
||||||
|
(* *********************************************************************** *)
|
||||||
|
(** * Delineating cases in proofs *)
|
||||||
|
|
||||||
|
(** This section was taken from the POPLmark Wiki
|
||||||
|
( http://alliance.seas.upenn.edu/~plclub/cgi-bin/poplmark/ ). *)
|
||||||
|
|
||||||
|
(** ** Tactic definitions *)
|
||||||
|
|
||||||
|
Ltac move_to_top x :=
|
||||||
|
match reverse goal with
|
||||||
|
| H : _ |- _ => try move x after H
|
||||||
|
end.
|
||||||
|
|
||||||
|
Tactic Notation "assert_eq" ident(x) constr(v) :=
|
||||||
|
let H := fresh in
|
||||||
|
assert (x = v) as H by reflexivity;
|
||||||
|
clear H.
|
||||||
|
|
||||||
|
Tactic Notation "Case_aux" ident(x) constr(name) :=
|
||||||
|
first [
|
||||||
|
set (x := name); move_to_top x
|
||||||
|
| assert_eq x name
|
||||||
|
| fail 1 "because we are working on a different case." ].
|
||||||
|
|
||||||
|
Ltac Case name := Case_aux case name.
|
||||||
|
Ltac SCase name := Case_aux subcase name.
|
||||||
|
Ltac SSCase name := Case_aux subsubcase name.
|
||||||
|
|
||||||
|
(** ** Example
|
||||||
|
|
||||||
|
One mode of use for the above tactics is to wrap Coq's [induction]
|
||||||
|
tactic such that automatically inserts "case" markers into each
|
||||||
|
branch of the proof. For example:
|
||||||
|
|
||||||
|
<<
|
||||||
|
Tactic Notation "induction" "nat" ident(n) :=
|
||||||
|
induction n; [ Case "O" | Case "S" ].
|
||||||
|
Tactic Notation "sub" "induction" "nat" ident(n) :=
|
||||||
|
induction n; [ SCase "O" | SCase "S" ].
|
||||||
|
Tactic Notation "sub" "sub" "induction" "nat" ident(n) :=
|
||||||
|
induction n; [ SSCase "O" | SSCase "S" ].
|
||||||
|
>>
|
||||||
|
|
||||||
|
If you use such customized versions of the induction tactics, then
|
||||||
|
the [Case] tactic will verify that you are working on the case
|
||||||
|
that you think you are. You may also use the [Case] tactic with
|
||||||
|
the standard version of [induction], in which case no verification
|
||||||
|
is done. *)
|
262
coq-Fsub/Atom.v
Normal file
262
coq-Fsub/Atom.v
Normal file
|
@ -0,0 +1,262 @@
|
||||||
|
(** Support for atoms, i.e., objects with decidable equality. We
|
||||||
|
provide here the ability to generate an atom fresh for any finite
|
||||||
|
collection, e.g., the lemma [atom_fresh_for_set], and a tactic to
|
||||||
|
pick an atom fresh for the current proof context.
|
||||||
|
|
||||||
|
Authors: Arthur Charguéraud and Brian Aydemir.
|
||||||
|
|
||||||
|
Implementation note: In older versions of Coq, [OrderedTypeEx]
|
||||||
|
redefines decimal constants to be integers and not natural
|
||||||
|
numbers. The following scope declaration is intended to address
|
||||||
|
this issue. In newer versions of Coq, the declaration should be
|
||||||
|
benign. *)
|
||||||
|
|
||||||
|
Require Import List.
|
||||||
|
Require Import Max.
|
||||||
|
Require Import OrderedType.
|
||||||
|
Require Import OrderedTypeEx.
|
||||||
|
Open Scope nat_scope.
|
||||||
|
|
||||||
|
Require Import FiniteSets.
|
||||||
|
Require Import FSetDecide.
|
||||||
|
Require Import FSetNotin.
|
||||||
|
Require Import ListFacts.
|
||||||
|
|
||||||
|
|
||||||
|
(* ********************************************************************** *)
|
||||||
|
(** * Definition *)
|
||||||
|
|
||||||
|
(** Atoms are structureless objects such that we can always generate
|
||||||
|
one fresh from a finite collection. Equality on atoms is [eq] and
|
||||||
|
decidable. We use Coq's module system to make abstract the
|
||||||
|
implementation of atoms. The [Export AtomImpl] line below allows
|
||||||
|
us to refer to the type [atom] and its properties without having
|
||||||
|
to qualify everything with "[AtomImpl.]". *)
|
||||||
|
|
||||||
|
Module Type ATOM.
|
||||||
|
|
||||||
|
Parameter atom : Set.
|
||||||
|
|
||||||
|
Parameter atom_fresh_for_list :
|
||||||
|
forall (xs : list atom), {x : atom | ~ List.In x xs}.
|
||||||
|
|
||||||
|
Declare Module Atom_as_OT : UsualOrderedType with Definition t := atom.
|
||||||
|
|
||||||
|
Parameter eq_atom_dec : forall x y : atom, {x = y} + {x <> y}.
|
||||||
|
|
||||||
|
End ATOM.
|
||||||
|
|
||||||
|
(** The implementation of the above interface is hidden for
|
||||||
|
documentation purposes. *)
|
||||||
|
|
||||||
|
Module AtomImpl : ATOM.
|
||||||
|
|
||||||
|
(* begin hide *)
|
||||||
|
|
||||||
|
Definition atom := nat.
|
||||||
|
|
||||||
|
Lemma max_lt_r : forall x y z,
|
||||||
|
x <= z -> x <= max y z.
|
||||||
|
Proof.
|
||||||
|
induction x. auto with arith.
|
||||||
|
induction y; auto with arith.
|
||||||
|
simpl. induction z. omega. auto with arith.
|
||||||
|
Qed.
|
||||||
|
|
||||||
|
Lemma nat_list_max : forall (xs : list nat),
|
||||||
|
{ n : nat | forall x, In x xs -> x <= n }.
|
||||||
|
Proof.
|
||||||
|
induction xs as [ | x xs [y H] ].
|
||||||
|
(* case: nil *)
|
||||||
|
exists 0. inversion 1.
|
||||||
|
(* case: cons x xs *)
|
||||||
|
exists (max x y). intros z J. simpl in J. destruct J as [K | K].
|
||||||
|
subst. auto with arith.
|
||||||
|
auto using max_lt_r.
|
||||||
|
Qed.
|
||||||
|
|
||||||
|
Lemma atom_fresh_for_list :
|
||||||
|
forall (xs : list nat), { n : nat | ~ List.In n xs }.
|
||||||
|
Proof.
|
||||||
|
intros xs. destruct (nat_list_max xs) as [x H].
|
||||||
|
exists (S x). intros J. lapply (H (S x)). omega. trivial.
|
||||||
|
Qed.
|
||||||
|
|
||||||
|
Module Atom_as_OT := Nat_as_OT.
|
||||||
|
Module Facts := OrderedTypeFacts Atom_as_OT.
|
||||||
|
|
||||||
|
Definition eq_atom_dec : forall x y : atom, {x = y} + {x <> y} :=
|
||||||
|
Facts.eq_dec.
|
||||||
|
|
||||||
|
(* end hide *)
|
||||||
|
|
||||||
|
End AtomImpl.
|
||||||
|
|
||||||
|
Export AtomImpl.
|
||||||
|
|
||||||
|
|
||||||
|
(* ********************************************************************** *)
|
||||||
|
(** * Finite sets of atoms *)
|
||||||
|
|
||||||
|
|
||||||
|
(* ********************************************************************** *)
|
||||||
|
(** ** Definitions *)
|
||||||
|
|
||||||
|
Module AtomSet : FiniteSets.S with Module E := Atom_as_OT :=
|
||||||
|
FiniteSets.Make Atom_as_OT.
|
||||||
|
|
||||||
|
(** The type [atoms] is the type of finite sets of [atom]s. *)
|
||||||
|
|
||||||
|
Notation atoms := AtomSet.F.t.
|
||||||
|
|
||||||
|
(** Basic operations on finite sets of atoms are available, in the
|
||||||
|
remainder of this file, without qualification. We use [Import]
|
||||||
|
instead of [Export] in order to avoid unnecessary namespace
|
||||||
|
pollution. *)
|
||||||
|
|
||||||
|
Import AtomSet.F.
|
||||||
|
|
||||||
|
(** We instantiate two modules which provide useful lemmas and tactics
|
||||||
|
work working with finite sets of atoms. *)
|
||||||
|
|
||||||
|
Module AtomSetDecide := FSetDecide.Decide AtomSet.F.
|
||||||
|
Module AtomSetNotin := FSetNotin.Notin AtomSet.F.
|
||||||
|
|
||||||
|
|
||||||
|
(* *********************************************************************** *)
|
||||||
|
(** ** Tactics for working with finite sets of atoms *)
|
||||||
|
|
||||||
|
(** The tactic [fsetdec] is a general purpose decision procedure
|
||||||
|
for solving facts about finite sets of atoms. *)
|
||||||
|
|
||||||
|
Ltac fsetdec := try apply AtomSet.eq_if_Equal; AtomSetDecide.fsetdec.
|
||||||
|
|
||||||
|
(** The tactic [notin_simpl] simplifies all hypotheses of the form [(~
|
||||||
|
In x F)], where [F] is constructed from the empty set, singleton
|
||||||
|
sets, and unions. *)
|
||||||
|
|
||||||
|
Ltac notin_simpl := AtomSetNotin.notin_simpl_hyps.
|
||||||
|
|
||||||
|
(** The tactic [notin_solve], solves goals of the form [(~ In x F)],
|
||||||
|
where [F] is constructed from the empty set, singleton sets, and
|
||||||
|
unions. The goal must be provable from hypothesis of the form
|
||||||
|
simplified by [notin_simpl]. *)
|
||||||
|
|
||||||
|
Ltac notin_solve := AtomSetNotin.notin_solve.
|
||||||
|
|
||||||
|
|
||||||
|
(* *********************************************************************** *)
|
||||||
|
(** ** Lemmas for working with finite sets of atoms *)
|
||||||
|
|
||||||
|
(** We make some lemmas about finite sets of atoms available without
|
||||||
|
qualification by using abbreviations. *)
|
||||||
|
|
||||||
|
Notation eq_if_Equal := AtomSet.eq_if_Equal.
|
||||||
|
Notation notin_empty := AtomSetNotin.notin_empty.
|
||||||
|
Notation notin_singleton := AtomSetNotin.notin_singleton.
|
||||||
|
Notation notin_singleton_rw := AtomSetNotin.notin_singleton_rw.
|
||||||
|
Notation notin_union := AtomSetNotin.notin_union.
|
||||||
|
|
||||||
|
|
||||||
|
(* ********************************************************************** *)
|
||||||
|
(** * Additional properties *)
|
||||||
|
|
||||||
|
(** One can generate an atom fresh for a given finite set of atoms. *)
|
||||||
|
|
||||||
|
Lemma atom_fresh_for_set : forall L : atoms, { x : atom | ~ In x L }.
|
||||||
|
Proof.
|
||||||
|
intros L. destruct (atom_fresh_for_list (elements L)) as [a H].
|
||||||
|
exists a. intros J. contradiction H.
|
||||||
|
rewrite <- InA_iff_In. auto using elements_1.
|
||||||
|
Qed.
|
||||||
|
|
||||||
|
|
||||||
|
(* ********************************************************************** *)
|
||||||
|
(** * Additional tactics *)
|
||||||
|
|
||||||
|
|
||||||
|
(* ********************************************************************** *)
|
||||||
|
(** ** #<a name="pick_fresh"></a># Picking a fresh atom *)
|
||||||
|
|
||||||
|
(** We define three tactics which, when combined, provide a simple
|
||||||
|
mechanism for picking a fresh atom. We demonstrate their use
|
||||||
|
below with an example, the [example_pick_fresh] tactic.
|
||||||
|
|
||||||
|
[(gather_atoms_with F)] returns the union of [(F x)], where [x]
|
||||||
|
ranges over all objects in the context such that [(F x)] is
|
||||||
|
well typed. The return type of [F] should be [atoms]. The
|
||||||
|
complexity of this tactic is due to the fact that there is no
|
||||||
|
support in [Ltac] for folding a function over the context. *)
|
||||||
|
|
||||||
|
Ltac gather_atoms_with F :=
|
||||||
|
let rec gather V :=
|
||||||
|
match goal with
|
||||||
|
| H: ?S |- _ =>
|
||||||
|
let FH := constr:(F H) in
|
||||||
|
match V with
|
||||||
|
| empty => gather FH
|
||||||
|
| context [FH] => fail 1
|
||||||
|
| _ => gather (union FH V)
|
||||||
|
end
|
||||||
|
| _ => V
|
||||||
|
end in
|
||||||
|
let L := gather empty in eval simpl in L.
|
||||||
|
|
||||||
|
(** [(beautify_fset V)] takes a set [V] built as a union of finite
|
||||||
|
sets and returns the same set with empty sets removed and union
|
||||||
|
operations associated to the right. Duplicate sets are also
|
||||||
|
removed from the union. *)
|
||||||
|
|
||||||
|
Ltac beautify_fset V :=
|
||||||
|
let rec go Acc E :=
|
||||||
|
match E with
|
||||||
|
| union ?E1 ?E2 => let Acc1 := go Acc E2 in go Acc1 E1
|
||||||
|
| empty => Acc
|
||||||
|
| ?E1 => match Acc with
|
||||||
|
| empty => E1
|
||||||
|
| context [E1] => Acc
|
||||||
|
| _ => constr:(union E1 Acc)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
in go empty V.
|
||||||
|
|
||||||
|
(** The tactic [(pick fresh Y for L)] takes a finite set of atoms [L]
|
||||||
|
and a fresh name [Y], and adds to the context an atom with name
|
||||||
|
[Y] and a proof that [(~ In Y L)], i.e., that [Y] is fresh for
|
||||||
|
[L]. The tactic will fail if [Y] is already declared in the
|
||||||
|
context. *)
|
||||||
|
|
||||||
|
Tactic Notation "pick" "fresh" ident(Y) "for" constr(L) :=
|
||||||
|
let Fr := fresh "Fr" in
|
||||||
|
let L := beautify_fset L in
|
||||||
|
(destruct (atom_fresh_for_set L) as [Y Fr]).
|
||||||
|
|
||||||
|
|
||||||
|
(* ********************************************************************** *)
|
||||||
|
(** ** Demonstration *)
|
||||||
|
|
||||||
|
(** The [example_pick_fresh] tactic below illustrates the general
|
||||||
|
pattern for using the above three tactics to define a tactic which
|
||||||
|
picks a fresh atom. The pattern is as follows:
|
||||||
|
- Repeatedly invoke [gather_atoms_with], using functions with
|
||||||
|
different argument types each time.
|
||||||
|
- Union together the result of the calls, and invoke
|
||||||
|
[(pick fresh ... for ...)] with that union of sets. *)
|
||||||
|
|
||||||
|
Ltac example_pick_fresh Y :=
|
||||||
|
let A := gather_atoms_with (fun x : atoms => x) in
|
||||||
|
let B := gather_atoms_with (fun x : atom => singleton x) in
|
||||||
|
pick fresh Y for (union A B).
|
||||||
|
|
||||||
|
Lemma example_pick_fresh_use : forall (x y z : atom) (L1 L2 L3: atoms), True.
|
||||||
|
(* begin show *)
|
||||||
|
Proof.
|
||||||
|
intros x y z L1 L2 L3. example_pick_fresh k.
|
||||||
|
|
||||||
|
(** At this point in the proof, we have a new atom [k] and a
|
||||||
|
hypothesis [Fr : ~ In k (union L1 (union L2 (union L3 (union
|
||||||
|
(singleton x) (union (singleton y) (singleton z))))))]. *)
|
||||||
|
|
||||||
|
trivial.
|
||||||
|
Qed.
|
||||||
|
(* end show *)
|
658
coq-Fsub/Environment.v
Normal file
658
coq-Fsub/Environment.v
Normal file
|
@ -0,0 +1,658 @@
|
||||||
|
(** Operations, lemmas, and tactics for working with environments,
|
||||||
|
association lists whose keys are atoms. Unless stated otherwise,
|
||||||
|
implicit arguments will not be declared by default.
|
||||||
|
|
||||||
|
Authors: Brian Aydemir and Arthur Charguéraud, with help from
|
||||||
|
Aaron Bohannon, Benjamin Pierce, Jeffrey Vaughan, Dimitrios
|
||||||
|
Vytiniotis, Stephanie Weirich, and Steve Zdancewic.
|
||||||
|
|
||||||
|
Table of contents:
|
||||||
|
- #<a href="##overview">Overview</a>#
|
||||||
|
- #<a href="##functions">Functions on environments</a>#
|
||||||
|
- #<a href="##env_rel">Relations on environments</a>#
|
||||||
|
- #<a href="##op_prop">Properties of operations</a>#
|
||||||
|
- #<a href="##auto1">Automation and tactics (I)</a>#
|
||||||
|
- #<a href="##props">Properties of well-formedness and freshness</a>#
|
||||||
|
- #<a href="##binds_prop">Properties of binds</a>#
|
||||||
|
- #<a href="##auto2">Automation and tactics (II)</a>#
|
||||||
|
- #<a href="##binds_prop2">Additional properties of binds</a>#
|
||||||
|
- #<a href="##auto3">Automation and tactics (III)</a># *)
|
||||||
|
|
||||||
|
Require Export List.
|
||||||
|
Require Export ListFacts.
|
||||||
|
Require Import Atom.
|
||||||
|
|
||||||
|
Import AtomSet.F.
|
||||||
|
Hint Local Unfold E.eq.
|
||||||
|
|
||||||
|
|
||||||
|
(* ********************************************************************** *)
|
||||||
|
(** * #<a name="overview"></a># Overview *)
|
||||||
|
|
||||||
|
(** An environment is a list of pairs, where the first component of
|
||||||
|
each pair is an [atom]. We view the second component of each pair
|
||||||
|
as being bound to the first component. In a well-formed
|
||||||
|
environment, there is at most one binding for any given atom.
|
||||||
|
Bindings at the head of the list are "more recent" than bindings
|
||||||
|
toward the tail of the list, and we view an environment as growing
|
||||||
|
on the left, i.e., at its head.
|
||||||
|
|
||||||
|
We normally work only with environments built up from the
|
||||||
|
following: the empty list, one element lists, and concatenations
|
||||||
|
of two lists. This seems to be more convenient in practice. For
|
||||||
|
example, we don't need to distinguish between consing on a binding
|
||||||
|
and concatenating a binding, a difference that Coq's tactics can
|
||||||
|
be sensitive to.
|
||||||
|
|
||||||
|
However, basic definitions are by induction on the usual structure
|
||||||
|
of lists ([nil] and [cons]).
|
||||||
|
|
||||||
|
To make it convenient to write one element lists, we define a
|
||||||
|
special notation. Note that this notation is local to this
|
||||||
|
particular library, to allow users to use alternate notations if
|
||||||
|
they desire. *)
|
||||||
|
|
||||||
|
Notation Local "[ x ]" := (cons x nil).
|
||||||
|
|
||||||
|
(** In the remainder of this library, we define a number of
|
||||||
|
operations, lemmas, and tactics that simplify working with
|
||||||
|
environments. *)
|
||||||
|
|
||||||
|
|
||||||
|
(* ********************************************************************** *)
|
||||||
|
(** * #<a name="functions"></a># Functions on environments *)
|
||||||
|
|
||||||
|
(** Implicit arguments will be declared by default for the definitions
|
||||||
|
in this section. *)
|
||||||
|
|
||||||
|
Set Implicit Arguments.
|
||||||
|
|
||||||
|
Section Definitions.
|
||||||
|
|
||||||
|
Variables A B : Type.
|
||||||
|
|
||||||
|
(** The domain of an environment is the set of atoms that it maps. *)
|
||||||
|
|
||||||
|
Fixpoint dom (E : list (atom * A)) : atoms :=
|
||||||
|
match E with
|
||||||
|
| nil => empty
|
||||||
|
| (x, _) :: E' => union (singleton x) (dom E')
|
||||||
|
end.
|
||||||
|
|
||||||
|
(** [map] applies a function to all bindings in the environment. *)
|
||||||
|
|
||||||
|
Fixpoint map (f : A -> B) (E : list (atom * A)) : list (atom * B) :=
|
||||||
|
match E with
|
||||||
|
| nil => nil
|
||||||
|
| (x, V) :: E' => (x, f V) :: map f E'
|
||||||
|
end.
|
||||||
|
|
||||||
|
(** [get] returns the value bound to the given atom in an environment
|
||||||
|
or [None] if the given atom is not bound. If the atom has
|
||||||
|
multiple bindings, the one nearest to the head of the environment
|
||||||
|
is returned. *)
|
||||||
|
|
||||||
|
Fixpoint get (x : atom) (E : list (atom * A)) : option A :=
|
||||||
|
match E with
|
||||||
|
| nil => None
|
||||||
|
| (y,a) :: E' => if eq_atom_dec x y then Some a else get x E'
|
||||||
|
end.
|
||||||
|
|
||||||
|
End Definitions.
|
||||||
|
|
||||||
|
Unset Implicit Arguments.
|
||||||
|
|
||||||
|
|
||||||
|
(* ********************************************************************** *)
|
||||||
|
(** * #<a name="env_rel"></a># Relations on environments *)
|
||||||
|
|
||||||
|
(** Implicit arguments will be declared by default for the definitions
|
||||||
|
in this section. *)
|
||||||
|
|
||||||
|
Set Implicit Arguments.
|
||||||
|
|
||||||
|
Section Relations.
|
||||||
|
|
||||||
|
Variable A : Type.
|
||||||
|
|
||||||
|
(** An environment is well-formed if and only if each atom is bound at
|
||||||
|
most once. *)
|
||||||
|
|
||||||
|
Inductive ok : list (atom * A) -> Prop :=
|
||||||
|
| ok_nil :
|
||||||
|
ok nil
|
||||||
|
| ok_cons : forall (E : list (atom * A)) (x : atom) (a : A),
|
||||||
|
ok E -> ~ In x (dom E) -> ok ((x, a) :: E).
|
||||||
|
|
||||||
|
(** #<a name="binds_doc"></a># An environment [E] contains a binding
|
||||||
|
from [x] to [b], denoted [(binds x b E)], if and only if the most
|
||||||
|
recent binding for [x] is mapped to [b]. *)
|
||||||
|
|
||||||
|
Definition binds x b (E : list (atom * A)) :=
|
||||||
|
get x E = Some b.
|
||||||
|
|
||||||
|
End Relations.
|
||||||
|
|
||||||
|
Unset Implicit Arguments.
|
||||||
|
|
||||||
|
|
||||||
|
(* ********************************************************************** *)
|
||||||
|
(** * #<a name="op_prop"></a># Properties of operations *)
|
||||||
|
|
||||||
|
Section OpProperties.
|
||||||
|
Variable A B : Type.
|
||||||
|
Implicit Types E F : list (atom * A).
|
||||||
|
Implicit Types a b : A.
|
||||||
|
|
||||||
|
(** ** Facts about concatenation *)
|
||||||
|
|
||||||
|
Lemma concat_nil : forall E,
|
||||||
|
E ++ nil = E.
|
||||||
|
Proof.
|
||||||
|
auto using List.app_nil_end.
|
||||||
|
Qed.
|
||||||
|
|
||||||
|
Lemma nil_concat : forall E,
|
||||||
|
nil ++ E = E.
|
||||||
|
Proof.
|
||||||
|
reflexivity.
|
||||||
|
Qed.
|
||||||
|
|
||||||
|
Lemma concat_assoc : forall E F G,
|
||||||
|
(G ++ F) ++ E = G ++ (F ++ E).
|
||||||
|
Proof.
|
||||||
|
auto using List.app_ass.
|
||||||
|
Qed.
|
||||||
|
|
||||||
|
(** ** [map] commutes with environment-building operations *)
|
||||||
|
|
||||||
|
Lemma map_nil : forall (f : A -> B),
|
||||||
|
map f nil = nil.
|
||||||
|
Proof.
|
||||||
|
reflexivity.
|
||||||
|
Qed.
|
||||||
|
|
||||||
|
Lemma map_single : forall (f : A -> B) y b,
|
||||||
|
map f [(y,b)] = [(y, f b)].
|
||||||
|
Proof.
|
||||||
|
reflexivity.
|
||||||
|
Qed.
|
||||||
|
|
||||||
|
Lemma map_push : forall (f : A -> B) y b E,
|
||||||
|
map f ([(y,b)] ++ E) = [(y, f b)] ++ map f E.
|
||||||
|
Proof.
|
||||||
|
reflexivity.
|
||||||
|
Qed.
|
||||||
|
|
||||||
|
Lemma map_concat : forall (f : A -> B) E F,
|
||||||
|
map f (F ++ E) = (map f F) ++ (map f E).
|
||||||
|
Proof.
|
||||||
|
induction F as [|(x,a)]; simpl; congruence.
|
||||||
|
Qed.
|
||||||
|
|
||||||
|
(** ** Facts about the domain of an environment *)
|
||||||
|
|
||||||
|
Lemma dom_nil :
|
||||||
|
@dom A nil = empty.
|
||||||
|
Proof.
|
||||||
|
reflexivity.
|
||||||
|
Qed.
|
||||||
|
|
||||||
|
Lemma dom_single : forall x a,
|
||||||
|
dom [(x,a)] = singleton x.
|
||||||
|
Proof.
|
||||||
|
simpl. intros. fsetdec.
|
||||||
|
Qed.
|
||||||
|
|
||||||
|
Lemma dom_push : forall x a E,
|
||||||
|
dom ([(x,a)] ++ E) = union (singleton x) (dom E).
|
||||||
|
Proof.
|
||||||
|
simpl. intros. reflexivity.
|
||||||
|
Qed.
|
||||||
|
|
||||||
|
Lemma dom_concat : forall E F,
|
||||||
|
dom (F ++ E) = union (dom F) (dom E).
|
||||||
|
Proof.
|
||||||
|
induction F as [|(x,a) F IH]; simpl.
|
||||||
|
fsetdec.
|
||||||
|
rewrite IH. fsetdec.
|
||||||
|
Qed.
|
||||||
|
|
||||||
|
Lemma dom_map : forall (f : A -> B) E,
|
||||||
|
dom (map f E) = dom E.
|
||||||
|
Proof.
|
||||||
|
induction E as [|(x,a)]; simpl; congruence.
|
||||||
|
Qed.
|
||||||
|
|
||||||
|
(** ** Other trivial rewrites *)
|
||||||
|
|
||||||
|
Lemma cons_concat_assoc : forall x a E F,
|
||||||
|
((x, a) :: E) ++ F = (x, a) :: (E ++ F).
|
||||||
|
Proof.
|
||||||
|
reflexivity.
|
||||||
|
Qed.
|
||||||
|
|
||||||
|
End OpProperties.
|
||||||
|
|
||||||
|
|
||||||
|
(* ********************************************************************** *)
|
||||||
|
(** * #<a name="auto1"></a># Automation and tactics (I) *)
|
||||||
|
|
||||||
|
(** ** [simpl_env] *)
|
||||||
|
|
||||||
|
(** The [simpl_env] tactic can be used to put environments in the
|
||||||
|
standardized form described above, with the additional properties
|
||||||
|
that concatenation is associated to the right and empty
|
||||||
|
environments are removed. Similar to the [simpl] tactic, we
|
||||||
|
define "[in *]" and "[in H]" variants of [simpl_env]. *)
|
||||||
|
|
||||||
|
Definition singleton_list (A : Type) (x : atom * A) := x :: nil.
|
||||||
|
Implicit Arguments singleton_list [A].
|
||||||
|
|
||||||
|
Lemma cons_concat : forall (A : Type) (E : list (atom * A)) x a,
|
||||||
|
(x, a) :: E = singleton_list (x, a) ++ E.
|
||||||
|
Proof.
|
||||||
|
reflexivity.
|
||||||
|
Qed.
|
||||||
|
|
||||||
|
Lemma map_singleton_list : forall (A B : Type) (f : A -> B) y b,
|
||||||
|
map f (singleton_list (y,b)) = [(y, f b)].
|
||||||
|
Proof.
|
||||||
|
reflexivity.
|
||||||
|
Qed.
|
||||||
|
|
||||||
|
Lemma dom_singleton_list : forall (A : Type) (x : atom) (a : A),
|
||||||
|
dom (singleton_list (x,a)) = singleton x.
|
||||||
|
Proof.
|
||||||
|
simpl. intros. fsetdec.
|
||||||
|
Qed.
|
||||||
|
|
||||||
|
Hint Rewrite
|
||||||
|
cons_concat map_singleton_list dom_singleton_list
|
||||||
|
concat_nil nil_concat concat_assoc
|
||||||
|
map_nil map_single map_push map_concat
|
||||||
|
dom_nil dom_single dom_push dom_concat dom_map : rew_env.
|
||||||
|
|
||||||
|
Ltac simpl_env_change_aux :=
|
||||||
|
match goal with
|
||||||
|
| H : context[?x :: nil] |- _ =>
|
||||||
|
progress (change (x :: nil) with (singleton_list x) in H);
|
||||||
|
simpl_env_change_aux
|
||||||
|
| |- context[?x :: nil] =>
|
||||||
|
progress (change (x :: nil) with (singleton_list x));
|
||||||
|
simpl_env_change_aux
|
||||||
|
| _ =>
|
||||||
|
idtac
|
||||||
|
end.
|
||||||
|
|
||||||
|
Ltac simpl_env :=
|
||||||
|
simpl_env_change_aux;
|
||||||
|
autorewrite with rew_env;
|
||||||
|
unfold singleton_list in *.
|
||||||
|
|
||||||
|
Tactic Notation "simpl_env" "in" hyp(H) :=
|
||||||
|
simpl_env_change_aux;
|
||||||
|
autorewrite with rew_env in H;
|
||||||
|
unfold singleton_list in *.
|
||||||
|
|
||||||
|
Tactic Notation "simpl_env" "in" "*" :=
|
||||||
|
simpl_env_change_aux;
|
||||||
|
autorewrite with rew_env in *;
|
||||||
|
unfold singleton_list in *.
|
||||||
|
|
||||||
|
(** ** [rewrite_env] *)
|
||||||
|
|
||||||
|
(** The tactic [(rewrite_env E)] replaces an environment in the
|
||||||
|
conclusion of the goal with [E]. Suitability for replacement is
|
||||||
|
determined by whether [simpl_env] can put [E] and the chosen
|
||||||
|
environment in the same normal form, up to convertability in Coq.
|
||||||
|
We also define a "[in H]" variant that performs the replacement in
|
||||||
|
a hypothesis [H]. *)
|
||||||
|
|
||||||
|
Tactic Notation "rewrite_env" constr(E) :=
|
||||||
|
match goal with
|
||||||
|
| |- context[?x] =>
|
||||||
|
change x with E
|
||||||
|
| |- context[?x] =>
|
||||||
|
replace x with E; [ | try reflexivity; simpl_env; reflexivity ]
|
||||||
|
end.
|
||||||
|
|
||||||
|
Tactic Notation "rewrite_env" constr(E) "in" hyp(H) :=
|
||||||
|
match type of H with
|
||||||
|
| context[?x] =>
|
||||||
|
change x with E in H
|
||||||
|
| context[?x] =>
|
||||||
|
replace x with E in H; [ | try reflexivity; simpl_env; reflexivity ]
|
||||||
|
end.
|
||||||
|
|
||||||
|
(** ** Hints *)
|
||||||
|
|
||||||
|
Hint Constructors ok.
|
||||||
|
|
||||||
|
Hint Local Extern 1 (~ In _ _) => simpl_env in *; fsetdec.
|
||||||
|
|
||||||
|
|
||||||
|
(* ********************************************************************** *)
|
||||||
|
(** * #<a name="props"></a># Properties of well-formedness and freshness *)
|
||||||
|
|
||||||
|
Section OkProperties.
|
||||||
|
Variable A B : Type.
|
||||||
|
Implicit Types E F : list (atom * A).
|
||||||
|
Implicit Types a b : A.
|
||||||
|
|
||||||
|
(** Facts about when an environment is well-formed. *)
|
||||||
|
|
||||||
|
Lemma ok_push : forall (E : list (atom * A)) (x : atom) (a : A),
|
||||||
|
ok E -> ~ In x (dom E) -> ok ([(x, a)] ++ E).
|
||||||
|
Proof.
|
||||||
|
exact (@ok_cons A).
|
||||||
|
Qed.
|
||||||
|
|
||||||
|
Lemma ok_singleton : forall x a,
|
||||||
|
ok [(x,a)].
|
||||||
|
Proof.
|
||||||
|
auto.
|
||||||
|
Qed.
|
||||||
|
|
||||||
|
Lemma ok_remove_mid : forall F E G,
|
||||||
|
ok (G ++ F ++ E) -> ok (G ++ E).
|
||||||
|
Proof with auto.
|
||||||
|
induction G as [|(y,a)]; intros Ok.
|
||||||
|
induction F as [|(y,a)]; simpl... inversion Ok...
|
||||||
|
inversion Ok. simpl...
|
||||||
|
Qed.
|
||||||
|
|
||||||
|
Lemma ok_remove_mid_cons : forall x a E G,
|
||||||
|
ok (G ++ (x, a) :: E) ->
|
||||||
|
ok (G ++ E).
|
||||||
|
Proof.
|
||||||
|
intros. simpl_env in *. eauto using ok_remove_mid.
|
||||||
|
Qed.
|
||||||
|
|
||||||
|
Lemma ok_map : forall E (f : A -> B),
|
||||||
|
ok E -> ok (map f E).
|
||||||
|
Proof with auto.
|
||||||
|
intros.
|
||||||
|
induction E as [ | (y,b) E ] ; simpl...
|
||||||
|
inversion H...
|
||||||
|
Qed.
|
||||||
|
|
||||||
|
Lemma ok_map_app_l : forall E F (f : A -> A),
|
||||||
|
ok (F ++ E) -> ok (map f F ++ E).
|
||||||
|
Proof with auto.
|
||||||
|
intros. induction F as [|(y,a)]; simpl...
|
||||||
|
inversion H...
|
||||||
|
Qed.
|
||||||
|
|
||||||
|
(** A binding in the middle of an environment has an atom fresh from
|
||||||
|
all bindings before and after it. *)
|
||||||
|
|
||||||
|
Lemma fresh_mid_tail : forall E F x a,
|
||||||
|
ok (F ++ [(x,a)] ++ E) -> ~ In x (dom E).
|
||||||
|
Proof with auto.
|
||||||
|
induction F as [|(y,b)]; intros x c Ok; simpl_env in *.
|
||||||
|
inversion Ok...
|
||||||
|
inversion Ok; subst. simpl_env in *. apply (IHF _ _ H1).
|
||||||
|
Qed.
|
||||||
|
|
||||||
|
Lemma fresh_mid_head : forall E F x a,
|
||||||
|
ok (F ++ [(x,a)] ++ E) -> ~ In x (dom F).
|
||||||
|
Proof with auto.
|
||||||
|
induction F as [|(y,b)]; intros x c Ok; simpl_env in *.
|
||||||
|
inversion Ok...
|
||||||
|
inversion Ok; subst. simpl_env in *. pose proof (IHF _ _ H1)...
|
||||||
|
Qed.
|
||||||
|
|
||||||
|
End OkProperties.
|
||||||
|
|
||||||
|
|
||||||
|
(* ********************************************************************** *)
|
||||||
|
(** * #<a name="binds_prop"></a># Properties of [binds] *)
|
||||||
|
|
||||||
|
Section BindsProperties.
|
||||||
|
Variable A B : Type.
|
||||||
|
Implicit Types E F : list (atom * A).
|
||||||
|
Implicit Types a b : A.
|
||||||
|
|
||||||
|
(** ** Introduction forms for [binds] *)
|
||||||
|
|
||||||
|
(** The following properties allow one to view [binds] as an
|
||||||
|
inductively defined predicate. This is the preferred way of
|
||||||
|
working with the relation. *)
|
||||||
|
|
||||||
|
Lemma binds_singleton : forall x a,
|
||||||
|
binds x a [(x,a)].
|
||||||
|
Proof.
|
||||||
|
intros x a. unfold binds. simpl. destruct (eq_atom_dec x x); intuition.
|
||||||
|
Qed.
|
||||||
|
|
||||||
|
Lemma binds_tail : forall x a E F,
|
||||||
|
binds x a E -> ~ In x (dom F) -> binds x a (F ++ E).
|
||||||
|
Proof with auto.
|
||||||
|
unfold binds. induction F as [|(y,b)]; simpl...
|
||||||
|
destruct (eq_atom_dec x y)... intros _ J. destruct J. fsetdec.
|
||||||
|
Qed.
|
||||||
|
|
||||||
|
Lemma binds_head : forall x a E F,
|
||||||
|
binds x a F -> binds x a (F ++ E).
|
||||||
|
Proof.
|
||||||
|
unfold binds. induction F as [|(y,b)]; simpl; intros H.
|
||||||
|
discriminate.
|
||||||
|
destruct (eq_atom_dec x y); intuition.
|
||||||
|
Qed.
|
||||||
|
|
||||||
|
(** ** Case analysis on [binds] *)
|
||||||
|
|
||||||
|
Lemma binds_concat_inv : forall x a E F,
|
||||||
|
binds x a (F ++ E) -> (~ In x (dom F) /\ binds x a E) \/ (binds x a F).
|
||||||
|
Proof with auto.
|
||||||
|
unfold binds. induction F as [|(y,b)]; simpl; intros H...
|
||||||
|
destruct (eq_atom_dec x y).
|
||||||
|
right...
|
||||||
|
destruct (IHF H) as [[? ?] | ?]. left... right...
|
||||||
|
Qed.
|
||||||
|
|
||||||
|
Lemma binds_singleton_inv : forall x y a b,
|
||||||
|
binds x a [(y,b)] -> x = y /\ a = b.
|
||||||
|
Proof.
|
||||||
|
unfold binds. simpl. intros. destruct (eq_atom_dec x y).
|
||||||
|
split; congruence.
|
||||||
|
discriminate.
|
||||||
|
Qed.
|
||||||
|
|
||||||
|
(** ** Retrieving bindings from an environment *)
|
||||||
|
|
||||||
|
Lemma binds_mid : forall x a E F,
|
||||||
|
ok (F ++ [(x,a)] ++ E) -> binds x a (F ++ [(x,a)] ++ E).
|
||||||
|
Proof with auto.
|
||||||
|
unfold binds. induction F as [|(z,b)]; simpl; intros Ok.
|
||||||
|
destruct (eq_atom_dec x x); intuition.
|
||||||
|
inversion Ok; subst. destruct (eq_atom_dec x z)...
|
||||||
|
destruct H3. simpl_env. fsetdec.
|
||||||
|
Qed.
|
||||||
|
|
||||||
|
Lemma binds_mid_eq : forall z a b E F,
|
||||||
|
binds z a (F ++ [(z,b)] ++ E) -> ok (F ++ [(z,b)] ++ E) -> a = b.
|
||||||
|
Proof with auto.
|
||||||
|
unfold binds. induction F as [|(x,c)]; simpl; intros H Ok.
|
||||||
|
destruct (eq_atom_dec z z). congruence. intuition.
|
||||||
|
inversion Ok; subst. destruct (eq_atom_dec z x)...
|
||||||
|
destruct H4. simpl_env. fsetdec.
|
||||||
|
Qed.
|
||||||
|
|
||||||
|
Lemma binds_mid_eq_cons : forall x a b E F,
|
||||||
|
binds x a (F ++ (x,b) :: E) ->
|
||||||
|
ok (F ++ (x,b) :: E) ->
|
||||||
|
a = b.
|
||||||
|
Proof.
|
||||||
|
intros. simpl_env in *. eauto using binds_mid_eq.
|
||||||
|
Qed.
|
||||||
|
|
||||||
|
End BindsProperties.
|
||||||
|
|
||||||
|
|
||||||
|
(* ********************************************************************** *)
|
||||||
|
(** * #<a name="auto2"></a># Automation and tactics (II) *)
|
||||||
|
|
||||||
|
(** ** Hints *)
|
||||||
|
|
||||||
|
Hint Immediate ok_remove_mid ok_remove_mid_cons.
|
||||||
|
|
||||||
|
Hint Resolve
|
||||||
|
ok_push ok_singleton ok_map ok_map_app_l
|
||||||
|
binds_singleton binds_head binds_tail.
|
||||||
|
|
||||||
|
(** ** [binds_get] *)
|
||||||
|
|
||||||
|
(** The tactic [(binds_get H)] takes a hypothesis [H] of the form
|
||||||
|
[(binds x a (F ++ [(x,b)] ++ E))] and introduces the equality
|
||||||
|
[a=b] into the context. Then, the tactic checks if the equality
|
||||||
|
is discriminable and otherwise tries substituting [b] for [a].
|
||||||
|
The [auto] tactic is used to show that [(ok (F ++ [(x,b)] ++ E))],
|
||||||
|
which is needed to prove the equality [a=b] from [H]. *)
|
||||||
|
|
||||||
|
Ltac binds_get H :=
|
||||||
|
match type of H with
|
||||||
|
| binds ?z ?a (?F ++ [(?z,?b)] ++ ?E) =>
|
||||||
|
let K := fresh in
|
||||||
|
assert (K : ok (F ++ [(z,b)] ++ E));
|
||||||
|
[ auto
|
||||||
|
| let J := fresh in
|
||||||
|
assert (J := @binds_mid_eq _ _ _ _ _ _ H K);
|
||||||
|
clear K;
|
||||||
|
try discriminate;
|
||||||
|
try match type of J with
|
||||||
|
| ?a = ?b => subst a
|
||||||
|
end
|
||||||
|
]
|
||||||
|
end.
|
||||||
|
|
||||||
|
(** ** [binds_cases] *)
|
||||||
|
|
||||||
|
(** The tactic [(binds_case H)] performs a case analysis on an
|
||||||
|
hypothesis [H] of the form [(binds x a E)]. There will be one
|
||||||
|
subgoal for each component of [E] that [x] could be bound in, and
|
||||||
|
each subgoal will have appropriate freshness conditions on [x].
|
||||||
|
Some attempts are made to automatically discharge contradictory
|
||||||
|
cases. *)
|
||||||
|
|
||||||
|
Ltac binds_cases H :=
|
||||||
|
let Fr := fresh "Fr" in
|
||||||
|
let J1 := fresh in
|
||||||
|
let J2 := fresh in
|
||||||
|
match type of H with
|
||||||
|
| binds _ _ nil =>
|
||||||
|
inversion H
|
||||||
|
| binds ?x ?a [(?y,?b)] =>
|
||||||
|
destruct (@binds_singleton_inv _ _ _ _ _ H);
|
||||||
|
clear H;
|
||||||
|
try discriminate;
|
||||||
|
try subst y;
|
||||||
|
try match goal with
|
||||||
|
| _ : ?z <> ?z |- _ => intuition
|
||||||
|
end
|
||||||
|
| binds ?x ?a (?F ++ ?E) =>
|
||||||
|
destruct (@binds_concat_inv _ _ _ _ _ H) as [[Fr J1] | J2];
|
||||||
|
clear H;
|
||||||
|
[ binds_cases J1 | binds_cases J2 ]
|
||||||
|
| _ => idtac
|
||||||
|
end.
|
||||||
|
|
||||||
|
|
||||||
|
(* *********************************************************************** *)
|
||||||
|
(** * #<a name="binds_prop2"></a># Additional properties of [binds] *)
|
||||||
|
|
||||||
|
(** The following lemmas are proven in manner that should be
|
||||||
|
independent of the concrete definition of [binds]. *)
|
||||||
|
|
||||||
|
Section AdditionalBindsProperties.
|
||||||
|
Variable A B : Type.
|
||||||
|
Implicit Types E F : list (atom * A).
|
||||||
|
Implicit Types a b : A.
|
||||||
|
|
||||||
|
(** Lemmas about the relationship between [binds] and the domain of an
|
||||||
|
environment. *)
|
||||||
|
|
||||||
|
Lemma binds_In : forall a x E,
|
||||||
|
binds x a E -> In x (dom E).
|
||||||
|
Proof.
|
||||||
|
induction E as [|(y,b)]; simpl_env; intros H.
|
||||||
|
binds_cases H.
|
||||||
|
binds_cases H; subst. auto using union_3. fsetdec.
|
||||||
|
Qed.
|
||||||
|
|
||||||
|
Lemma binds_fresh : forall x a E,
|
||||||
|
~ In x (dom E) -> ~ binds x a E.
|
||||||
|
Proof.
|
||||||
|
induction E as [|(y,b)]; simpl_env; intros Fresh H.
|
||||||
|
binds_cases H.
|
||||||
|
binds_cases H. intuition. fsetdec.
|
||||||
|
Qed.
|
||||||
|
|
||||||
|
(** Additional lemmas for showing that a binding is in an
|
||||||
|
environment. *)
|
||||||
|
|
||||||
|
Lemma binds_map : forall x a (f : A -> B) E,
|
||||||
|
binds x a E -> binds x (f a) (map f E).
|
||||||
|
Proof.
|
||||||
|
induction E as [|(y,b)]; simpl_env; intros H.
|
||||||
|
binds_cases H.
|
||||||
|
binds_cases H; auto. subst; auto.
|
||||||
|
Qed.
|
||||||
|
|
||||||
|
Lemma binds_concat_ok : forall x a E F,
|
||||||
|
binds x a E -> ok (F ++ E) -> binds x a (F ++ E).
|
||||||
|
Proof.
|
||||||
|
induction F as [|(y,b)]; simpl_env; intros H Ok.
|
||||||
|
auto.
|
||||||
|
inversion Ok; subst. destruct (eq_atom_dec x y); subst; auto.
|
||||||
|
assert (In y (dom (F ++ E))) by eauto using binds_In.
|
||||||
|
intuition.
|
||||||
|
Qed.
|
||||||
|
|
||||||
|
Lemma binds_weaken : forall x a E F G,
|
||||||
|
binds x a (G ++ E) ->
|
||||||
|
ok (G ++ F ++ E) ->
|
||||||
|
binds x a (G ++ F ++ E).
|
||||||
|
Proof.
|
||||||
|
induction G as [|(y,b)]; simpl_env; intros H Ok.
|
||||||
|
auto using binds_concat_ok.
|
||||||
|
inversion Ok; subst. binds_cases H; subst; auto.
|
||||||
|
Qed.
|
||||||
|
|
||||||
|
Lemma binds_weaken_at_head : forall x a F G,
|
||||||
|
binds x a G ->
|
||||||
|
ok (F ++ G) ->
|
||||||
|
binds x a (F ++ G).
|
||||||
|
Proof.
|
||||||
|
intros x a F G H J.
|
||||||
|
rewrite_env (nil ++ F ++ G).
|
||||||
|
apply binds_weaken; simpl_env; trivial.
|
||||||
|
Qed.
|
||||||
|
|
||||||
|
Lemma binds_remove_mid : forall x y a b F G,
|
||||||
|
binds x a (F ++ [(y,b)] ++ G) ->
|
||||||
|
x <> y ->
|
||||||
|
binds x a (F ++ G).
|
||||||
|
Proof.
|
||||||
|
intros x y a b F G H J.
|
||||||
|
binds_cases H; auto.
|
||||||
|
Qed.
|
||||||
|
|
||||||
|
Lemma binds_remove_mid_cons : forall x y a b E G,
|
||||||
|
binds x a (G ++ (y, b) :: E) ->
|
||||||
|
x <> y ->
|
||||||
|
binds x a (G ++ E).
|
||||||
|
Proof.
|
||||||
|
intros. simpl_env in *. eauto using binds_remove_mid.
|
||||||
|
Qed.
|
||||||
|
|
||||||
|
End AdditionalBindsProperties.
|
||||||
|
|
||||||
|
|
||||||
|
(* *********************************************************************** *)
|
||||||
|
(** * #<a name="auto3"></a># Automation and tactics (III) *)
|
||||||
|
|
||||||
|
Hint Resolve binds_map binds_concat_ok binds_weaken binds_weaken_at_head.
|
||||||
|
|
||||||
|
Hint Immediate binds_remove_mid binds_remove_mid_cons.
|
1052
coq-Fsub/FSetDecide.v
Normal file
1052
coq-Fsub/FSetDecide.v
Normal file
File diff suppressed because it is too large
Load diff
164
coq-Fsub/FSetNotin.v
Normal file
164
coq-Fsub/FSetNotin.v
Normal file
|
@ -0,0 +1,164 @@
|
||||||
|
(** Lemmas and tactics for working with and solving goals related to
|
||||||
|
non-membership in finite sets. The main tactic of interest here
|
||||||
|
is [notin_solve].
|
||||||
|
|
||||||
|
Authors: Arthur Charguéraud and Brian Aydemir. *)
|
||||||
|
|
||||||
|
Set Implicit Arguments.
|
||||||
|
Require Import FSetInterface.
|
||||||
|
|
||||||
|
|
||||||
|
(* *********************************************************************** *)
|
||||||
|
(** * Implementation *)
|
||||||
|
|
||||||
|
Module Notin (X : FSetInterface.S).
|
||||||
|
|
||||||
|
Import X.
|
||||||
|
|
||||||
|
|
||||||
|
(* *********************************************************************** *)
|
||||||
|
(** ** Facts about set (non-)membership *)
|
||||||
|
|
||||||
|
Lemma in_singleton : forall x,
|
||||||
|
In x (singleton x).
|
||||||
|
Proof.
|
||||||
|
auto using singleton_2.
|
||||||
|
Qed.
|
||||||
|
|
||||||
|
Lemma notin_empty : forall x,
|
||||||
|
~ In x empty.
|
||||||
|
Proof.
|
||||||
|
auto using empty_1.
|
||||||
|
Qed.
|
||||||
|
|
||||||
|
Lemma notin_union : forall x E F,
|
||||||
|
~ In x E -> ~ In x F -> ~ In x (union E F).
|
||||||
|
Proof.
|
||||||
|
intros x E F H J K.
|
||||||
|
destruct (union_1 K); intuition.
|
||||||
|
Qed.
|
||||||
|
|
||||||
|
Lemma elim_notin_union : forall x E F,
|
||||||
|
~ In x (union E F) -> (~ In x E) /\ (~ In x F).
|
||||||
|
Proof.
|
||||||
|
intros x E F H. split; intros J; contradiction H.
|
||||||
|
auto using union_2.
|
||||||
|
auto using union_3.
|
||||||
|
Qed.
|
||||||
|
|
||||||
|
Lemma notin_singleton : forall x y,
|
||||||
|
~ E.eq x y -> ~ In x (singleton y).
|
||||||
|
Proof.
|
||||||
|
intros x y H J. assert (K := singleton_1 J). intuition.
|
||||||
|
Qed.
|
||||||
|
|
||||||
|
Lemma elim_notin_singleton : forall x y,
|
||||||
|
~ In x (singleton y) -> ~ E.eq x y.
|
||||||
|
Proof.
|
||||||
|
intros x y H J. contradiction H. auto using singleton_2.
|
||||||
|
Qed.
|
||||||
|
|
||||||
|
Lemma elim_notin_singleton' : forall x y,
|
||||||
|
~ In x (singleton y) -> x <> y.
|
||||||
|
Proof.
|
||||||
|
intros. assert (~ E.eq x y). auto using singleton_2.
|
||||||
|
intros J. subst. intuition.
|
||||||
|
Qed.
|
||||||
|
|
||||||
|
Lemma notin_singleton_swap : forall x y,
|
||||||
|
~ In x (singleton y) -> ~ In y (singleton x).
|
||||||
|
Proof.
|
||||||
|
intros.
|
||||||
|
assert (Q := elim_notin_singleton H).
|
||||||
|
auto using singleton_1.
|
||||||
|
Qed.
|
||||||
|
|
||||||
|
|
||||||
|
(* *********************************************************************** *)
|
||||||
|
(** ** Rewriting non-membership facts *)
|
||||||
|
|
||||||
|
Lemma notin_singleton_rw : forall x y,
|
||||||
|
~ In x (singleton y) <-> ~ E.eq x y.
|
||||||
|
Proof.
|
||||||
|
intros. split.
|
||||||
|
auto using elim_notin_singleton.
|
||||||
|
auto using notin_singleton.
|
||||||
|
Qed.
|
||||||
|
|
||||||
|
|
||||||
|
(* *********************************************************************** *)
|
||||||
|
(** ** Tactics *)
|
||||||
|
|
||||||
|
(** The tactic [notin_simpl_hyps] destructs all hypotheses of the form
|
||||||
|
[(~ In x E)], where [E] is built using only [empty], [union], and
|
||||||
|
[singleton]. *)
|
||||||
|
|
||||||
|
Ltac notin_simpl_hyps :=
|
||||||
|
try match goal with
|
||||||
|
| H: In ?x ?E -> False |- _ =>
|
||||||
|
change (~ In x E) in H;
|
||||||
|
notin_simpl_hyps
|
||||||
|
| H: ~ In _ empty |- _ =>
|
||||||
|
clear H;
|
||||||
|
notin_simpl_hyps
|
||||||
|
| H: ~ In ?x (singleton ?y) |- _ =>
|
||||||
|
let F1 := fresh in
|
||||||
|
let F2 := fresh in
|
||||||
|
assert (F1 := @elim_notin_singleton x y H);
|
||||||
|
assert (F2 := @elim_notin_singleton' x y H);
|
||||||
|
clear H;
|
||||||
|
notin_simpl_hyps
|
||||||
|
| H: ~ In ?x (union ?E ?F) |- _ =>
|
||||||
|
destruct (@elim_notin_union x E F H);
|
||||||
|
clear H;
|
||||||
|
notin_simpl_hyps
|
||||||
|
end.
|
||||||
|
|
||||||
|
(** The tactic [notin_solve] solves goals of them form [(x <> y)] and
|
||||||
|
[(~ In x E)] that are provable from hypotheses of the form
|
||||||
|
destructed by [notin_simpl_hyps]. *)
|
||||||
|
|
||||||
|
Ltac notin_solve :=
|
||||||
|
notin_simpl_hyps;
|
||||||
|
repeat (progress ( apply notin_empty
|
||||||
|
|| apply notin_union
|
||||||
|
|| apply notin_singleton));
|
||||||
|
solve [ trivial | congruence | intuition auto ].
|
||||||
|
|
||||||
|
|
||||||
|
(* *********************************************************************** *)
|
||||||
|
(** ** Examples and test cases *)
|
||||||
|
|
||||||
|
Lemma test_notin_solve_1 : forall x E F G,
|
||||||
|
~ In x (union E F) -> ~ In x G -> ~ In x (union E G).
|
||||||
|
Proof.
|
||||||
|
intros. notin_solve.
|
||||||
|
Qed.
|
||||||
|
|
||||||
|
Lemma test_notin_solve_2 : forall x y E F G,
|
||||||
|
~ In x (union E (union (singleton y) F)) -> ~ In x G ->
|
||||||
|
~ In x (singleton y) /\ ~ In y (singleton x).
|
||||||
|
Proof.
|
||||||
|
intros. split. notin_solve. notin_solve.
|
||||||
|
Qed.
|
||||||
|
|
||||||
|
Lemma test_notin_solve_3 : forall x y,
|
||||||
|
~ E.eq x y -> ~ In x (singleton y) /\ ~ In y (singleton x).
|
||||||
|
Proof.
|
||||||
|
intros. split. notin_solve. notin_solve.
|
||||||
|
Qed.
|
||||||
|
|
||||||
|
Lemma test_notin_solve_4 : forall x y E F G,
|
||||||
|
~ In x (union E (union (singleton x) F)) -> ~ In y G.
|
||||||
|
Proof.
|
||||||
|
intros. notin_solve.
|
||||||
|
Qed.
|
||||||
|
|
||||||
|
Lemma test_notin_solve_5 : forall x y E F,
|
||||||
|
~ In x (union E (union (singleton y) F)) -> ~ In y E ->
|
||||||
|
~ E.eq y x /\ ~ E.eq x y.
|
||||||
|
Proof.
|
||||||
|
intros. split. notin_solve. notin_solve.
|
||||||
|
Qed.
|
||||||
|
|
||||||
|
End Notin.
|
61
coq-Fsub/FiniteSets.v
Normal file
61
coq-Fsub/FiniteSets.v
Normal file
|
@ -0,0 +1,61 @@
|
||||||
|
(** A library for finite sets with extensional equality.
|
||||||
|
|
||||||
|
Author: Brian Aydemir. *)
|
||||||
|
|
||||||
|
Require Import FSets.
|
||||||
|
Require Import ListFacts.
|
||||||
|
|
||||||
|
|
||||||
|
(* *********************************************************************** *)
|
||||||
|
(** * Interface *)
|
||||||
|
|
||||||
|
(** The following interface wraps the standard library's finite set
|
||||||
|
interface with an additional property: extensional equality. *)
|
||||||
|
|
||||||
|
Module Type S.
|
||||||
|
|
||||||
|
Declare Module E : UsualOrderedType.
|
||||||
|
Declare Module F : FSetInterface.S with Module E := E.
|
||||||
|
|
||||||
|
Parameter eq_if_Equal :
|
||||||
|
forall s s' : F.t, F.Equal s s' -> s = s'.
|
||||||
|
|
||||||
|
End S.
|
||||||
|
|
||||||
|
|
||||||
|
(* *********************************************************************** *)
|
||||||
|
(** * Implementation *)
|
||||||
|
|
||||||
|
(** For documentation purposes, we hide the implementation of a
|
||||||
|
functor implementing the above interface. We note only that the
|
||||||
|
implementation here assumes (as an axiom) that proof irrelevance
|
||||||
|
holds. *)
|
||||||
|
|
||||||
|
Module Make (X : UsualOrderedType) <: S with Module E := X.
|
||||||
|
|
||||||
|
(* begin hide *)
|
||||||
|
|
||||||
|
Module E := X.
|
||||||
|
Module F := FSetList.Make E.
|
||||||
|
Module OFacts := OrderedType.OrderedTypeFacts E.
|
||||||
|
|
||||||
|
Axiom sort_F_E_lt_proof_irrel : forall xs (p q : sort F.E.lt xs), p = q.
|
||||||
|
|
||||||
|
Lemma eq_if_Equal :
|
||||||
|
forall s s' : F.t, F.Equal s s' -> s = s'.
|
||||||
|
Proof.
|
||||||
|
intros [s1 pf1] [s2 pf2] Eq.
|
||||||
|
assert (s1 = s2).
|
||||||
|
unfold F.Raw.t in *.
|
||||||
|
eapply Sort_InA_eq_ext; eauto.
|
||||||
|
intros; eapply E.lt_trans; eauto.
|
||||||
|
intros; eapply OFacts.lt_eq; eauto.
|
||||||
|
intros; eapply OFacts.eq_lt; eauto.
|
||||||
|
subst s1.
|
||||||
|
rewrite (sort_F_E_lt_proof_irrel _ pf1 pf2).
|
||||||
|
reflexivity.
|
||||||
|
Qed.
|
||||||
|
|
||||||
|
(* end hide *)
|
||||||
|
|
||||||
|
End Make.
|
493
coq-Fsub/Fsub_Definitions.v
Normal file
493
coq-Fsub/Fsub_Definitions.v
Normal file
|
@ -0,0 +1,493 @@
|
||||||
|
(** Definition of Fsub (System F with subtyping).
|
||||||
|
|
||||||
|
Authors: Brian Aydemir and Arthur Charguéraud, with help from
|
||||||
|
Aaron Bohannon, Jeffrey Vaughan, and Dimitrios Vytiniotis.
|
||||||
|
|
||||||
|
Table of contents:
|
||||||
|
- #<a href="##syntax">Syntax (pre-terms)</a>#
|
||||||
|
- #<a href="##open">Opening</a>#
|
||||||
|
- #<a href="##lc">Local closure</a>#
|
||||||
|
- #<a href="##env">Environments</a>#
|
||||||
|
- #<a href="##wf">Well-formedness</a>#
|
||||||
|
- #<a href="##sub">Subtyping</a>#
|
||||||
|
- #<a href="##typing_doc">Typing</a>#
|
||||||
|
- #<a href="##values">Values</a>#
|
||||||
|
- #<a href="##reduction">Reduction</a>#
|
||||||
|
- #<a href="##auto">Automation</a>#
|
||||||
|
*)
|
||||||
|
|
||||||
|
Require Export Metatheory.
|
||||||
|
|
||||||
|
|
||||||
|
(* ********************************************************************** *)
|
||||||
|
(** * #<a name="syntax"></a># Syntax (pre-terms) *)
|
||||||
|
|
||||||
|
(** We use a locally nameless representation for Fsub, where bound
|
||||||
|
variables are represented as natural numbers (de Bruijn indices)
|
||||||
|
and free variables are represented as [atom]s. The type [atom],
|
||||||
|
defined in the [Atom] library, represents names: there are
|
||||||
|
infinitely many atoms, equality is decidable on atoms, and it is
|
||||||
|
possible to generate an atom fresh for any given finite set of
|
||||||
|
atoms.
|
||||||
|
|
||||||
|
We say that the definitions below define pre-types ([typ]) and
|
||||||
|
pre-expressions ([exp]), collectively pre-terms, since the
|
||||||
|
datatypes admit terms, such as [(typ_all typ_top (typ_bvar 3))],
|
||||||
|
where indices are unbound. A term is locally closed when it
|
||||||
|
contains no unbound indices.
|
||||||
|
|
||||||
|
Note that indices for bound type variables are distinct from
|
||||||
|
indices for bound expression variables. We make this explicit in
|
||||||
|
the definitions below of the opening operations. *)
|
||||||
|
|
||||||
|
Inductive typ : Set :=
|
||||||
|
| typ_top : typ
|
||||||
|
| typ_bvar : nat -> typ
|
||||||
|
| typ_fvar : atom -> typ
|
||||||
|
| typ_arrow : typ -> typ -> typ
|
||||||
|
| typ_all : typ -> typ -> typ
|
||||||
|
.
|
||||||
|
|
||||||
|
Inductive exp : Set :=
|
||||||
|
| exp_bvar : nat -> exp
|
||||||
|
| exp_fvar : atom -> exp
|
||||||
|
| exp_abs : typ -> exp -> exp
|
||||||
|
| exp_app : exp -> exp -> exp
|
||||||
|
| exp_tabs : typ -> exp -> exp
|
||||||
|
| exp_tapp : exp -> typ -> exp
|
||||||
|
.
|
||||||
|
|
||||||
|
(** We declare the constructors for indices and variables to be
|
||||||
|
coercions. For example, if Coq sees a [nat] where it expects an
|
||||||
|
[exp], it will implicitly insert an application of [exp_bvar];
|
||||||
|
similar behavior happens for [atom]s. Thus, we may write
|
||||||
|
[(exp_abs typ_top (exp_app 0 x))] instead of [(exp_abs typ_top
|
||||||
|
(exp_app (exp_bvar 0) (exp_fvar x)))]. *)
|
||||||
|
|
||||||
|
Coercion typ_bvar : nat >-> typ.
|
||||||
|
Coercion typ_fvar : atom >-> typ.
|
||||||
|
Coercion exp_bvar : nat >-> exp.
|
||||||
|
Coercion exp_fvar : atom >-> exp.
|
||||||
|
|
||||||
|
|
||||||
|
(* ********************************************************************** *)
|
||||||
|
(** * #<a name="open"></a># Opening terms *)
|
||||||
|
|
||||||
|
(** Opening replaces an index with a term. This operation is required
|
||||||
|
if we wish to work only with locally closed terms when going under
|
||||||
|
binders (e.g., the typing rule for [exp_abs]). It also
|
||||||
|
corresponds to informal substitution for a bound variable, which
|
||||||
|
occurs in the rule for beta reduction.
|
||||||
|
|
||||||
|
We need to define three functions for opening due the syntax of
|
||||||
|
Fsub, and we name them according to the following convention.
|
||||||
|
- [tt]: Denotes an operation involving types appearing in types.
|
||||||
|
- [te]: Denotes an operation involving types appearing in
|
||||||
|
expressions.
|
||||||
|
- [ee]: Denotes an operation involving expressions appearing in
|
||||||
|
expressions.
|
||||||
|
|
||||||
|
The notation used below for decidable equality on atoms and
|
||||||
|
natural numbers (e.g., [K === J]) is defined in the [Metatheory]
|
||||||
|
library. The order of arguments to each "open" function is the
|
||||||
|
same. For example, [(open_tt_rec K U T)] can be read as
|
||||||
|
"substitute [U] for index [K] in [T]."
|
||||||
|
|
||||||
|
Note that we assume that [U] is locally closed (and similarly for
|
||||||
|
the other opening functions). This assumption simplifies the
|
||||||
|
implementations of opening by letting us avoid shifting. Since
|
||||||
|
bound variables are indices, there is no need to rename variables
|
||||||
|
to avoid capture. Finally, we assume that these functions are
|
||||||
|
initially called with index zero and that zero is the only unbound
|
||||||
|
index in the term. This eliminates the need to possibly subtract
|
||||||
|
one in the case of indices. *)
|
||||||
|
|
||||||
|
Fixpoint open_tt_rec (K : nat) (U : typ) (T : typ) {struct T} : typ :=
|
||||||
|
match T with
|
||||||
|
| typ_top => typ_top
|
||||||
|
| typ_bvar J => if K === J then U else (typ_bvar J)
|
||||||
|
| typ_fvar X => typ_fvar X
|
||||||
|
| typ_arrow T1 T2 => typ_arrow (open_tt_rec K U T1) (open_tt_rec K U T2)
|
||||||
|
| typ_all T1 T2 => typ_all (open_tt_rec K U T1) (open_tt_rec (S K) U T2)
|
||||||
|
end.
|
||||||
|
|
||||||
|
Fixpoint open_te_rec (K : nat) (U : typ) (e : exp) {struct e} : exp :=
|
||||||
|
match e with
|
||||||
|
| exp_bvar i => exp_bvar i
|
||||||
|
| exp_fvar x => exp_fvar x
|
||||||
|
| exp_abs V e1 => exp_abs (open_tt_rec K U V) (open_te_rec K U e1)
|
||||||
|
| exp_app e1 e2 => exp_app (open_te_rec K U e1) (open_te_rec K U e2)
|
||||||
|
| exp_tabs V e1 => exp_tabs (open_tt_rec K U V) (open_te_rec (S K) U e1)
|
||||||
|
| exp_tapp e1 V => exp_tapp (open_te_rec K U e1) (open_tt_rec K U V)
|
||||||
|
end.
|
||||||
|
|
||||||
|
Fixpoint open_ee_rec (k : nat) (f : exp) (e : exp) {struct e} : exp :=
|
||||||
|
match e with
|
||||||
|
| exp_bvar i => if k === i then f else (exp_bvar i)
|
||||||
|
| exp_fvar x => exp_fvar x
|
||||||
|
| exp_abs V e1 => exp_abs V (open_ee_rec (S k) f e1)
|
||||||
|
| exp_app e1 e2 => exp_app (open_ee_rec k f e1) (open_ee_rec k f e2)
|
||||||
|
| exp_tabs V e1 => exp_tabs V (open_ee_rec k f e1)
|
||||||
|
| exp_tapp e1 V => exp_tapp (open_ee_rec k f e1) V
|
||||||
|
end.
|
||||||
|
|
||||||
|
(** Many common applications of opening replace index zero with an
|
||||||
|
expression or variable. The following definitions provide
|
||||||
|
convenient shorthands for such uses. Note that the order of
|
||||||
|
arguments is switched relative to the definitions above. For
|
||||||
|
example, [(open_tt T X)] can be read as "substitute the variable
|
||||||
|
[X] for index [0] in [T]" and "open [T] with the variable [X]."
|
||||||
|
Recall that the coercions above let us write [X] in place of
|
||||||
|
[(typ_fvar X)], assuming that [X] is an [atom]. *)
|
||||||
|
|
||||||
|
Definition open_tt T U := open_tt_rec 0 U T.
|
||||||
|
Definition open_te e U := open_te_rec 0 U e.
|
||||||
|
Definition open_ee e1 e2 := open_ee_rec 0 e2 e1.
|
||||||
|
|
||||||
|
|
||||||
|
(* ********************************************************************** *)
|
||||||
|
(** * #<a name="lc"></a># Local closure *)
|
||||||
|
|
||||||
|
(** Recall that [typ] and [exp] define pre-terms; these datatypes
|
||||||
|
admit terms that contain unbound indices. A term is locally
|
||||||
|
closed, or syntactically well-formed, when no indices appearing in
|
||||||
|
it are unbound. The proposition [(type T)] holds when a type [T]
|
||||||
|
is locally closed, and [(expr e)] holds when an expression [e] is
|
||||||
|
locally closed.
|
||||||
|
|
||||||
|
The inductive definitions below formalize local closure such that
|
||||||
|
the resulting induction principles serve as structural induction
|
||||||
|
principles over (locally closed) types and (locally closed)
|
||||||
|
expressions. In particular, unlike the situation with pre-terms,
|
||||||
|
there are no cases for indices. Thus, these induction principles
|
||||||
|
correspond more closely to informal practice than the ones arising
|
||||||
|
from the definitions of pre-terms.
|
||||||
|
|
||||||
|
The interesting cases in the inductive definitions below are those
|
||||||
|
that involve binding constructs, e.g., [typ_all]. Intuitively, to
|
||||||
|
check if the pre-term [(typ_all T1 T2)] is locally closed we much
|
||||||
|
check that [T1] is locally closed, and that [T2] is locally closed
|
||||||
|
when opened with a variable. However, there is a choice as to how
|
||||||
|
many variables to quantify over. One possibility is to quantify
|
||||||
|
over only one variable ("existential" quantification), as in
|
||||||
|
<<
|
||||||
|
type_all : forall X T1 T2,
|
||||||
|
type T1 ->
|
||||||
|
type (open_tt T2 X) ->
|
||||||
|
type (typ_all T1 T2)
|
||||||
|
>> or we could quantify over as many variables as possible ("universal"
|
||||||
|
quantification), as in
|
||||||
|
<<
|
||||||
|
type_all : forall T1 T2,
|
||||||
|
type T1 ->
|
||||||
|
(forall X : atom, type (open_tt T2 X)) ->
|
||||||
|
type (typ_all T1 T2)
|
||||||
|
>> It is possible to show that the resulting relations are equivalent.
|
||||||
|
The former makes it easy to build derivations, while the latter
|
||||||
|
provides a strong induction principle. McKinna and Pollack used
|
||||||
|
both forms of this relation in their work on formalizing Pure Type
|
||||||
|
Systems.
|
||||||
|
|
||||||
|
We take a different approach here and use "cofinite
|
||||||
|
quantification": we quantify over all but finitely many variables.
|
||||||
|
This approach provides a convenient middle ground: we can build
|
||||||
|
derivations reasonably easily and get reasonably strong induction
|
||||||
|
principles. With some work, one can show that the definitions
|
||||||
|
below are equivalent to ones that use existential, and hence also
|
||||||
|
universal, quantification. *)
|
||||||
|
|
||||||
|
Inductive type : typ -> Prop :=
|
||||||
|
| type_top :
|
||||||
|
type typ_top
|
||||||
|
| type_var : forall X,
|
||||||
|
type (typ_fvar X)
|
||||||
|
| type_arrow : forall T1 T2,
|
||||||
|
type T1 ->
|
||||||
|
type T2 ->
|
||||||
|
type (typ_arrow T1 T2)
|
||||||
|
| type_all : forall L T1 T2,
|
||||||
|
type T1 ->
|
||||||
|
(forall X : atom, X `notin` L -> type (open_tt T2 X)) ->
|
||||||
|
type (typ_all T1 T2)
|
||||||
|
.
|
||||||
|
|
||||||
|
Inductive expr : exp -> Prop :=
|
||||||
|
| expr_var : forall x,
|
||||||
|
expr (exp_fvar x)
|
||||||
|
| expr_abs : forall L T e1,
|
||||||
|
type T ->
|
||||||
|
(forall x : atom, x `notin` L -> expr (open_ee e1 x)) ->
|
||||||
|
expr (exp_abs T e1)
|
||||||
|
| expr_app : forall e1 e2,
|
||||||
|
expr e1 ->
|
||||||
|
expr e2 ->
|
||||||
|
expr (exp_app e1 e2)
|
||||||
|
| expr_tabs : forall L T e1,
|
||||||
|
type T ->
|
||||||
|
(forall X : atom, X `notin` L -> expr (open_te e1 X)) ->
|
||||||
|
expr (exp_tabs T e1)
|
||||||
|
| expr_tapp : forall e1 V,
|
||||||
|
expr e1 ->
|
||||||
|
type V ->
|
||||||
|
expr (exp_tapp e1 V)
|
||||||
|
.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
(* ********************************************************************** *)
|
||||||
|
(** * #<a name="env"></a># Environments *)
|
||||||
|
|
||||||
|
(** In our presentation of System F with subtyping, we use a single
|
||||||
|
environment for both typing and subtyping assumptions. We
|
||||||
|
formalize environments by representing them as association lists
|
||||||
|
(lists of pairs of keys and values) whose keys are atoms.
|
||||||
|
|
||||||
|
The [Metatheory] and [Environment] libraries provide functions,
|
||||||
|
predicates, tactics, notations and lemmas that simplify working
|
||||||
|
with environments. The [Environment] library treats environments
|
||||||
|
as lists of type [list (atom * A)].
|
||||||
|
|
||||||
|
Since environments map [atom]s, the type [A] should encode whether
|
||||||
|
a particular binding is a typing or subtyping assumption. Thus,
|
||||||
|
we instantiate [A] with the type [binding], defined below. *)
|
||||||
|
|
||||||
|
Inductive binding : Set :=
|
||||||
|
| bind_sub : typ -> binding
|
||||||
|
| bind_typ : typ -> binding.
|
||||||
|
|
||||||
|
(** A binding [(X, bind_sub T)] records that a type variable [X] is a
|
||||||
|
subtype of [T], and a binding [(x, bind_typ U)] records that an
|
||||||
|
expression variable [x] has type [U].
|
||||||
|
|
||||||
|
We define an abbreviation [env] for the type of environments, and
|
||||||
|
an abbreviation [empty] for the empty environment.
|
||||||
|
|
||||||
|
Note: Each instance of [Notation] below defines an abbreviation
|
||||||
|
since the left-hand side consists of a single identifier that is
|
||||||
|
not in quotes. These abbreviations are used for both parsing (the
|
||||||
|
left-hand side is equivalent to the right-hand side in all
|
||||||
|
contexts) and printing (the right-hand side is pretty-printed as
|
||||||
|
the left-hand side). Since [nil] is normally a polymorphic
|
||||||
|
constructor whose type argument is implicit, we prefix the name
|
||||||
|
with "[@]" to signal to Coq that we are going to supply arguments
|
||||||
|
to [nil] explicitly. *)
|
||||||
|
|
||||||
|
Notation env := (list (atom * binding)).
|
||||||
|
Notation empty := (@nil (atom * binding)).
|
||||||
|
|
||||||
|
(** We also define a notation that makes it convenient to write one
|
||||||
|
element lists. This notation is useful because of our convention
|
||||||
|
for building environments; see the examples below. *)
|
||||||
|
|
||||||
|
Notation "[ x ]" := (x :: nil).
|
||||||
|
|
||||||
|
(** #<b>#Examples:#</b># We use a convention where environments are
|
||||||
|
never built using a cons operation [((x, a) :: E)] where [E] is
|
||||||
|
non-[nil]. This makes the shape of environments more uniform and
|
||||||
|
saves us from excessive fiddling with the shapes of environments.
|
||||||
|
For example, Coq's tactics sometimes distinguish between consing
|
||||||
|
on a new binding and prepending a one element list, even though
|
||||||
|
the two operations are convertible with each other.
|
||||||
|
|
||||||
|
Consider the following environments written in informal notation.
|
||||||
|
<<
|
||||||
|
1. (empty environment)
|
||||||
|
2. x : T
|
||||||
|
3. x : T, Y <: S
|
||||||
|
4. E, x : T, F
|
||||||
|
>> In the third example, we have an environment that binds an
|
||||||
|
expression variable [x] to [T] and a type variable [Y] to [S].
|
||||||
|
In Coq, we would write these environments as follows.
|
||||||
|
<<
|
||||||
|
1. empty
|
||||||
|
2. [(x, bind_typ T)]
|
||||||
|
3. [(Y, bind_sub S)] ++ [(x, bind_typ T)]
|
||||||
|
4. F ++ [(x, bind_typ T)] ++ E
|
||||||
|
>> The symbol "[++]" denotes list concatenation and associates to the
|
||||||
|
right. (That notation is defined in Coq's [List] library.) Note
|
||||||
|
that in Coq, environments grow on the left, since that is where
|
||||||
|
the head of a list is. *)
|
||||||
|
|
||||||
|
|
||||||
|
(* ********************************************************************** *)
|
||||||
|
(** * #<a name="wf"></a># Well-formedness *)
|
||||||
|
|
||||||
|
(** A type [T] is well-formed with respect to an environment [E],
|
||||||
|
denoted [(wf_typ E T)], when [T] is locally-closed and its free
|
||||||
|
variables are bound in [E]. We need this relation in order to
|
||||||
|
restrict the subtyping and typing relations, defined below, to
|
||||||
|
contain only well-formed types. (This relation is missing in the
|
||||||
|
original statement of the POPLmark Challenge.)
|
||||||
|
|
||||||
|
Note: It is tempting to define the premise of [wf_typ_var] as [(X
|
||||||
|
`in` dom E)], since that makes the rule easier to apply (no need
|
||||||
|
to guess an instantiation for [U]). Unfortunately, this is
|
||||||
|
incorrect. We need to check that [X] is bound as a type-variable,
|
||||||
|
not an expression-variable; [(dom E)] does not distinguish between
|
||||||
|
the two kinds of bindings. *)
|
||||||
|
|
||||||
|
Inductive wf_typ : env -> typ -> Prop :=
|
||||||
|
| wf_typ_top : forall E,
|
||||||
|
wf_typ E typ_top
|
||||||
|
| wf_typ_var : forall U E (X : atom),
|
||||||
|
binds X (bind_sub U) E ->
|
||||||
|
wf_typ E (typ_fvar X)
|
||||||
|
| wf_typ_arrow : forall E T1 T2,
|
||||||
|
wf_typ E T1 ->
|
||||||
|
wf_typ E T2 ->
|
||||||
|
wf_typ E (typ_arrow T1 T2)
|
||||||
|
| wf_typ_all : forall L E T1 T2,
|
||||||
|
wf_typ E T1 ->
|
||||||
|
(forall X : atom, X `notin` L ->
|
||||||
|
wf_typ ([(X, bind_sub T1)] ++ E) (open_tt T2 X)) ->
|
||||||
|
wf_typ E (typ_all T1 T2)
|
||||||
|
.
|
||||||
|
|
||||||
|
(** An environment E is well-formed, denoted [(wf_env E)], if each
|
||||||
|
atom is bound at most at once and if each binding is to a
|
||||||
|
well-formed type. This is a stronger relation than the [ok]
|
||||||
|
relation defined in the [Environment] library. We need this
|
||||||
|
relation in order to restrict the subtyping and typing relations,
|
||||||
|
defined below, to contain only well-formed environments. (This
|
||||||
|
relation is missing in the original statement of the POPLmark
|
||||||
|
Challenge.) *)
|
||||||
|
|
||||||
|
Inductive wf_env : env -> Prop :=
|
||||||
|
| wf_env_empty :
|
||||||
|
wf_env empty
|
||||||
|
| wf_env_sub : forall (E : env) (X : atom) (T : typ),
|
||||||
|
wf_env E ->
|
||||||
|
wf_typ E T ->
|
||||||
|
X `notin` dom E ->
|
||||||
|
wf_env ([(X, bind_sub T)] ++ E)
|
||||||
|
| wf_env_typ : forall (E : env) (x : atom) (T : typ),
|
||||||
|
wf_env E ->
|
||||||
|
wf_typ E T ->
|
||||||
|
x `notin` dom E ->
|
||||||
|
wf_env ([(x, bind_typ T)] ++ E).
|
||||||
|
|
||||||
|
|
||||||
|
(* ********************************************************************** *)
|
||||||
|
(** * #<a name="sub"></a># Subtyping *)
|
||||||
|
|
||||||
|
(** The definition of subtyping is straightforward. It uses the
|
||||||
|
[binds] relation from the [Environment] library (in the
|
||||||
|
[sub_trans_tvar] case) and cofinite quantification (in the
|
||||||
|
[sub_all] case). *)
|
||||||
|
|
||||||
|
Inductive sub : env -> typ -> typ -> Prop :=
|
||||||
|
| sub_top : forall E S,
|
||||||
|
wf_env E ->
|
||||||
|
wf_typ E S ->
|
||||||
|
sub E S typ_top
|
||||||
|
| sub_refl_tvar : forall E X,
|
||||||
|
wf_env E ->
|
||||||
|
wf_typ E (typ_fvar X) ->
|
||||||
|
sub E (typ_fvar X) (typ_fvar X)
|
||||||
|
| sub_trans_tvar : forall U E T X,
|
||||||
|
binds X (bind_sub U) E ->
|
||||||
|
sub E U T ->
|
||||||
|
sub E (typ_fvar X) T
|
||||||
|
| sub_arrow : forall E S1 S2 T1 T2,
|
||||||
|
sub E T1 S1 ->
|
||||||
|
sub E S2 T2 ->
|
||||||
|
sub E (typ_arrow S1 S2) (typ_arrow T1 T2)
|
||||||
|
| sub_all : forall L E S1 S2 T1 T2,
|
||||||
|
sub E T1 S1 ->
|
||||||
|
(forall X : atom, X `notin` L ->
|
||||||
|
sub ([(X, bind_sub T1)] ++ E) (open_tt S2 X) (open_tt T2 X)) ->
|
||||||
|
sub E (typ_all S1 S2) (typ_all T1 T2)
|
||||||
|
.
|
||||||
|
|
||||||
|
|
||||||
|
(* ********************************************************************** *)
|
||||||
|
(** * #<a name="typing_doc"></a># Typing *)
|
||||||
|
|
||||||
|
(** The definition of typing is straightforward. It uses the [binds]
|
||||||
|
relation from the [Environment] library (in the [typing_var] case)
|
||||||
|
and cofinite quantification in the cases involving binders (e.g.,
|
||||||
|
[typing_abs] and [typing_tabs]). *)
|
||||||
|
|
||||||
|
Inductive typing : env -> exp -> typ -> Prop :=
|
||||||
|
| typing_var : forall E x T,
|
||||||
|
wf_env E ->
|
||||||
|
binds x (bind_typ T) E ->
|
||||||
|
typing E (exp_fvar x) T
|
||||||
|
| typing_abs : forall L E V e1 T1,
|
||||||
|
(forall x : atom, x `notin` L ->
|
||||||
|
typing ([(x, bind_typ V)] ++ E) (open_ee e1 x) T1) ->
|
||||||
|
typing E (exp_abs V e1) (typ_arrow V T1)
|
||||||
|
| typing_app : forall T1 E e1 e2 T2,
|
||||||
|
typing E e1 (typ_arrow T1 T2) ->
|
||||||
|
typing E e2 T1 ->
|
||||||
|
typing E (exp_app e1 e2) T2
|
||||||
|
| typing_tabs : forall L E V e1 T1,
|
||||||
|
(forall X : atom, X `notin` L ->
|
||||||
|
typing ([(X, bind_sub V)] ++ E) (open_te e1 X) (open_tt T1 X)) ->
|
||||||
|
typing E (exp_tabs V e1) (typ_all V T1)
|
||||||
|
| typing_tapp : forall T1 E e1 T T2,
|
||||||
|
typing E e1 (typ_all T1 T2) ->
|
||||||
|
sub E T T1 ->
|
||||||
|
typing E (exp_tapp e1 T) (open_tt T2 T)
|
||||||
|
| typing_sub : forall S E e T,
|
||||||
|
typing E e S ->
|
||||||
|
sub E S T ->
|
||||||
|
typing E e T
|
||||||
|
.
|
||||||
|
|
||||||
|
|
||||||
|
(* ********************************************************************** *)
|
||||||
|
(** * #<a name="values"></a># Values *)
|
||||||
|
|
||||||
|
Inductive value : exp -> Prop :=
|
||||||
|
| value_abs : forall T e1,
|
||||||
|
expr (exp_abs T e1) ->
|
||||||
|
value (exp_abs T e1)
|
||||||
|
| value_tabs : forall T e1,
|
||||||
|
expr (exp_tabs T e1) ->
|
||||||
|
value (exp_tabs T e1)
|
||||||
|
.
|
||||||
|
|
||||||
|
|
||||||
|
(* ********************************************************************** *)
|
||||||
|
(** * #<a name="reduction"></a># Reduction *)
|
||||||
|
|
||||||
|
Inductive red : exp -> exp -> Prop :=
|
||||||
|
| red_app_1 : forall e1 e1' e2,
|
||||||
|
expr e2 ->
|
||||||
|
red e1 e1' ->
|
||||||
|
red (exp_app e1 e2) (exp_app e1' e2)
|
||||||
|
| red_app_2 : forall e1 e2 e2',
|
||||||
|
value e1 ->
|
||||||
|
red e2 e2' ->
|
||||||
|
red (exp_app e1 e2) (exp_app e1 e2')
|
||||||
|
| red_tapp : forall e1 e1' V,
|
||||||
|
type V ->
|
||||||
|
red e1 e1' ->
|
||||||
|
red (exp_tapp e1 V) (exp_tapp e1' V)
|
||||||
|
| red_abs : forall T e1 v2,
|
||||||
|
expr (exp_abs T e1) ->
|
||||||
|
value v2 ->
|
||||||
|
red (exp_app (exp_abs T e1) v2) (open_ee e1 v2)
|
||||||
|
| red_tabs : forall T1 e1 T2,
|
||||||
|
expr (exp_tabs T1 e1) ->
|
||||||
|
type T2 ->
|
||||||
|
red (exp_tapp (exp_tabs T1 e1) T2) (open_te e1 T2)
|
||||||
|
.
|
||||||
|
|
||||||
|
|
||||||
|
(* ********************************************************************** *)
|
||||||
|
(** * #<a name="auto"></a># Automation *)
|
||||||
|
|
||||||
|
(** We declare most constructors as [Hint]s to be used by the [auto]
|
||||||
|
and [eauto] tactics. We exclude constructors from the subtyping
|
||||||
|
and typing relations that use cofinite quantification. It is
|
||||||
|
unlikely that [eauto] will find an instantiation for the finite
|
||||||
|
set [L], and in those cases, [eauto] can take some time to fail.
|
||||||
|
(A priori, this is not obvious. In practice, one adds as hints
|
||||||
|
all constructors and then later removes some constructors when
|
||||||
|
they cause proof search to take too long.) *)
|
||||||
|
|
||||||
|
Hint Constructors type expr wf_typ wf_env value red.
|
||||||
|
Hint Resolve sub_top sub_refl_tvar sub_arrow.
|
||||||
|
Hint Resolve typing_var typing_app typing_tapp typing_sub.
|
665
coq-Fsub/Fsub_Infrastructure.v
Normal file
665
coq-Fsub/Fsub_Infrastructure.v
Normal file
|
@ -0,0 +1,665 @@
|
||||||
|
(** Infrastructure lemmas and tactic definitions for Fsub.
|
||||||
|
|
||||||
|
Authors: Brian Aydemir and Arthur Charguéraud, with help from
|
||||||
|
Aaron Bohannon, Jeffrey Vaughan, and Dimitrios Vytiniotis.
|
||||||
|
|
||||||
|
This file contains a number of definitions, tactics, and lemmas
|
||||||
|
that are based only on the syntax of the language at hand. While
|
||||||
|
the exact statements of everything here would change for a
|
||||||
|
different language, the general structure of this file (i.e., the
|
||||||
|
sequence of definitions, tactics, and lemmas) would remain the
|
||||||
|
same.
|
||||||
|
|
||||||
|
Table of contents:
|
||||||
|
- #<a href="##fv">Free variables</a>#
|
||||||
|
- #<a href="##subst">Substitution</a>#
|
||||||
|
- #<a href="##pick_fresh">The "pick fresh" tactic</a>#
|
||||||
|
- #<a href="##apply_fresh">The "pick fresh and apply" tactic</a>#
|
||||||
|
- #<a href="##properties">Properties of opening and substitution</a>#
|
||||||
|
- #<a href="##lc">Local closure is preserved under substitution</a>#
|
||||||
|
- #<a href="##auto">Automation</a># *)
|
||||||
|
|
||||||
|
|
||||||
|
Require Export Fsub_Definitions.
|
||||||
|
|
||||||
|
|
||||||
|
(* ********************************************************************** *)
|
||||||
|
(** * #<a name="fv"></a># Free variables *)
|
||||||
|
|
||||||
|
(** In this section, we define free variable functions. The functions
|
||||||
|
[fv_tt] and [fv_te] calculate the set of atoms used as free type
|
||||||
|
variables in a type or expression, respectively. The function
|
||||||
|
[fv_ee] calculates the set of atoms used as free expression
|
||||||
|
variables in an expression. Cases involving binders are
|
||||||
|
straightforward since bound variables are indices, not names, in
|
||||||
|
locally nameless representation. *)
|
||||||
|
|
||||||
|
Fixpoint fv_tt (T : typ) {struct T} : atoms :=
|
||||||
|
match T with
|
||||||
|
| typ_top => {}
|
||||||
|
| typ_bvar J => {}
|
||||||
|
| typ_fvar X => singleton X
|
||||||
|
| typ_arrow T1 T2 => (fv_tt T1) `union` (fv_tt T2)
|
||||||
|
| typ_all T1 T2 => (fv_tt T1) `union` (fv_tt T2)
|
||||||
|
end.
|
||||||
|
|
||||||
|
Fixpoint fv_te (e : exp) {struct e} : atoms :=
|
||||||
|
match e with
|
||||||
|
| exp_bvar i => {}
|
||||||
|
| exp_fvar x => {}
|
||||||
|
| exp_abs V e1 => (fv_tt V) `union` (fv_te e1)
|
||||||
|
| exp_app e1 e2 => (fv_te e1) `union` (fv_te e2)
|
||||||
|
| exp_tabs V e1 => (fv_tt V) `union` (fv_te e1)
|
||||||
|
| exp_tapp e1 V => (fv_tt V) `union` (fv_te e1)
|
||||||
|
end.
|
||||||
|
|
||||||
|
Fixpoint fv_ee (e : exp) {struct e} : atoms :=
|
||||||
|
match e with
|
||||||
|
| exp_bvar i => {}
|
||||||
|
| exp_fvar x => singleton x
|
||||||
|
| exp_abs V e1 => (fv_ee e1)
|
||||||
|
| exp_app e1 e2 => (fv_ee e1) `union` (fv_ee e2)
|
||||||
|
| exp_tabs V e1 => (fv_ee e1)
|
||||||
|
| exp_tapp e1 V => (fv_ee e1)
|
||||||
|
end.
|
||||||
|
|
||||||
|
|
||||||
|
(* ********************************************************************** *)
|
||||||
|
(** * #<a name="subst"></a># Substitution *)
|
||||||
|
|
||||||
|
(** In this section, we define substitution for expression and type
|
||||||
|
variables appearing in types, expressions, and environments.
|
||||||
|
Substitution differs from opening because opening replaces indices
|
||||||
|
whereas substitution replaces free variables. The definitions
|
||||||
|
below are relatively simple for two reasons.
|
||||||
|
- We are using locally nameless representation, where bound
|
||||||
|
variables are represented using indices. Thus, there is no
|
||||||
|
need to rename variables to avoid capture.
|
||||||
|
- The definitions below assume that the term being substituted
|
||||||
|
in, i.e., the second argument to each function, is locally
|
||||||
|
closed. Thus, there is no need to shift indices when passing
|
||||||
|
under a binder. *)
|
||||||
|
|
||||||
|
Fixpoint subst_tt (Z : atom) (U : typ) (T : typ) {struct T} : typ :=
|
||||||
|
match T with
|
||||||
|
| typ_top => typ_top
|
||||||
|
| typ_bvar J => typ_bvar J
|
||||||
|
| typ_fvar X => if X == Z then U else T
|
||||||
|
| typ_arrow T1 T2 => typ_arrow (subst_tt Z U T1) (subst_tt Z U T2)
|
||||||
|
| typ_all T1 T2 => typ_all (subst_tt Z U T1) (subst_tt Z U T2)
|
||||||
|
end.
|
||||||
|
|
||||||
|
Fixpoint subst_te (Z : atom) (U : typ) (e : exp) {struct e} : exp :=
|
||||||
|
match e with
|
||||||
|
| exp_bvar i => exp_bvar i
|
||||||
|
| exp_fvar x => exp_fvar x
|
||||||
|
| exp_abs V e1 => exp_abs (subst_tt Z U V) (subst_te Z U e1)
|
||||||
|
| exp_app e1 e2 => exp_app (subst_te Z U e1) (subst_te Z U e2)
|
||||||
|
| exp_tabs V e1 => exp_tabs (subst_tt Z U V) (subst_te Z U e1)
|
||||||
|
| exp_tapp e1 V => exp_tapp (subst_te Z U e1) (subst_tt Z U V)
|
||||||
|
end.
|
||||||
|
|
||||||
|
Fixpoint subst_ee (z : atom) (u : exp) (e : exp) {struct e} : exp :=
|
||||||
|
match e with
|
||||||
|
| exp_bvar i => exp_bvar i
|
||||||
|
| exp_fvar x => if x == z then u else e
|
||||||
|
| exp_abs V e1 => exp_abs V (subst_ee z u e1)
|
||||||
|
| exp_app e1 e2 => exp_app (subst_ee z u e1) (subst_ee z u e2)
|
||||||
|
| exp_tabs V e1 => exp_tabs V (subst_ee z u e1)
|
||||||
|
| exp_tapp e1 V => exp_tapp (subst_ee z u e1) V
|
||||||
|
end.
|
||||||
|
|
||||||
|
Definition subst_tb (Z : atom) (P : typ) (b : binding) : binding :=
|
||||||
|
match b with
|
||||||
|
| bind_sub T => bind_sub (subst_tt Z P T)
|
||||||
|
| bind_typ T => bind_typ (subst_tt Z P T)
|
||||||
|
end.
|
||||||
|
|
||||||
|
|
||||||
|
(* ********************************************************************** *)
|
||||||
|
(** * #<a name="pick_fresh"></a># The "[pick fresh]" tactic *)
|
||||||
|
|
||||||
|
(** The "[pick fresh]" tactic introduces a fresh atom into the context.
|
||||||
|
We define it in two steps.
|
||||||
|
|
||||||
|
The first step is to define an auxiliary tactic [gather_atoms],
|
||||||
|
meant to be used in the definition of other tactics, which returns
|
||||||
|
a set of atoms in the current context. The definition of
|
||||||
|
[gather_atoms] follows a pattern based on repeated calls to
|
||||||
|
[gather_atoms_with]. The one argument to this tactic is a
|
||||||
|
function that takes an object of some particular type and returns
|
||||||
|
a set of atoms that appear in that argument. It is not necessary
|
||||||
|
to understand exactly how [gather_atoms_with] works. If we add a
|
||||||
|
new inductive datatype, say for kinds, to our language, then we
|
||||||
|
would need to modify [gather_atoms]. On the other hand, if we
|
||||||
|
merely add a new type, say products, then there is no need to
|
||||||
|
modify [gather_atoms]; the required changes would be made in
|
||||||
|
[fv_tt]. *)
|
||||||
|
|
||||||
|
Ltac gather_atoms :=
|
||||||
|
let A := gather_atoms_with (fun x : atoms => x) in
|
||||||
|
let B := gather_atoms_with (fun x : atom => singleton x) in
|
||||||
|
let C := gather_atoms_with (fun x : exp => fv_te x) in
|
||||||
|
let D := gather_atoms_with (fun x : exp => fv_ee x) in
|
||||||
|
let E := gather_atoms_with (fun x : typ => fv_tt x) in
|
||||||
|
let F := gather_atoms_with (fun x : env => dom x) in
|
||||||
|
constr:(A `union` B `union` C `union` D `union` E `union` F).
|
||||||
|
|
||||||
|
(** The second step in defining "[pick fresh]" is to define the tactic
|
||||||
|
itself. It is based on the [(pick fresh ... for ...)] tactic
|
||||||
|
defined in the [Atom] library. Here, we use [gather_atoms] to
|
||||||
|
construct the set [L] rather than leaving it to the user to
|
||||||
|
provide. Thus, invoking [(pick fresh x)] introduces a new atom
|
||||||
|
[x] into the current context that is fresh for "everything" in the
|
||||||
|
context. *)
|
||||||
|
|
||||||
|
Tactic Notation "pick" "fresh" ident(x) :=
|
||||||
|
let L := gather_atoms in (pick fresh x for L).
|
||||||
|
|
||||||
|
|
||||||
|
(* *********************************************************************** *)
|
||||||
|
(** * #<a name="apply_fresh"></a># The "[pick fresh and apply]" tactic *)
|
||||||
|
|
||||||
|
(** This tactic is implementation specific only because of its
|
||||||
|
reliance on [gather_atoms], which is itself implementation
|
||||||
|
specific. The definition below may be copied between developments
|
||||||
|
without any changes, assuming that the other other developments
|
||||||
|
define an appropriate [gather_atoms] tactic. For documentation on
|
||||||
|
the tactic on which the one below is based, see the
|
||||||
|
[Metatheory] library. *)
|
||||||
|
|
||||||
|
Tactic Notation
|
||||||
|
"pick" "fresh" ident(atom_name) "and" "apply" constr(lemma) :=
|
||||||
|
let L := gather_atoms in
|
||||||
|
pick fresh atom_name excluding L and apply lemma.
|
||||||
|
|
||||||
|
|
||||||
|
(* ********************************************************************** *)
|
||||||
|
(** * #<a name="properties"></a># Properties of opening and substitution *)
|
||||||
|
|
||||||
|
(** The following lemmas provide useful structural properties of
|
||||||
|
substitution and opening. While the exact statements are language
|
||||||
|
specific, we have found that similar properties are needed in a
|
||||||
|
wide range of languages.
|
||||||
|
|
||||||
|
Below, we indicate which lemmas depend on which other lemmas.
|
||||||
|
Since [te] functions depend on their [tt] counterparts, a similar
|
||||||
|
dependency can be found in the lemmas.
|
||||||
|
|
||||||
|
The lemmas are split into three sections, one each for the [tt],
|
||||||
|
[te], and [ee] functions. The most important lemmas are the
|
||||||
|
following:
|
||||||
|
- Substitution and opening commute with each other, e.g.,
|
||||||
|
[subst_tt_open_tt_var].
|
||||||
|
- Opening a term is equivalent to opening the term with a fresh
|
||||||
|
name and then substituting for that name, e.g.,
|
||||||
|
[subst_tt_intro].
|
||||||
|
|
||||||
|
We keep the sections as uniform in structure as possible. In
|
||||||
|
particular, we state explicitly strengthened induction hypotheses
|
||||||
|
even when there are more concise ways of proving the lemmas of
|
||||||
|
interest. *)
|
||||||
|
|
||||||
|
|
||||||
|
(* ********************************************************************** *)
|
||||||
|
(** ** Properties of type substitution in types *)
|
||||||
|
|
||||||
|
(** The next lemma is the strengthened induction hypothesis for the
|
||||||
|
lemma that follows, which states that opening a locally closed
|
||||||
|
term is the identity. This lemma is not otherwise independently
|
||||||
|
useful. *)
|
||||||
|
|
||||||
|
Lemma open_tt_rec_type_aux : forall T j V i U,
|
||||||
|
i <> j ->
|
||||||
|
open_tt_rec j V T = open_tt_rec i U (open_tt_rec j V T) ->
|
||||||
|
T = open_tt_rec i U T.
|
||||||
|
Proof with eauto*.
|
||||||
|
induction T; intros j V i U Neq H; simpl in *; inversion H; f_equal...
|
||||||
|
Case "typ_bvar".
|
||||||
|
destruct (j === n)... destruct (i === n)...
|
||||||
|
Qed.
|
||||||
|
|
||||||
|
(** Opening a locally closed term is the identity. This lemma depends
|
||||||
|
on the immediately preceding lemma. *)
|
||||||
|
|
||||||
|
Lemma open_tt_rec_type : forall T U k,
|
||||||
|
type T ->
|
||||||
|
T = open_tt_rec k U T.
|
||||||
|
Proof with auto*.
|
||||||
|
intros T U k Htyp. revert k.
|
||||||
|
induction Htyp; intros k; simpl; f_equal...
|
||||||
|
Case "typ_all".
|
||||||
|
unfold open_tt in *.
|
||||||
|
pick fresh X.
|
||||||
|
apply (open_tt_rec_type_aux T2 0 (typ_fvar X))...
|
||||||
|
Qed.
|
||||||
|
|
||||||
|
(** If a name is fresh for a term, then substituting for it is the
|
||||||
|
identity. *)
|
||||||
|
|
||||||
|
Lemma subst_tt_fresh : forall Z U T,
|
||||||
|
Z `notin` fv_tt T ->
|
||||||
|
T = subst_tt Z U T.
|
||||||
|
Proof with auto*.
|
||||||
|
induction T; simpl; intro H; f_equal...
|
||||||
|
Case "typ_fvar".
|
||||||
|
destruct (a == Z)...
|
||||||
|
absurd_hyp H; fsetdec.
|
||||||
|
Qed.
|
||||||
|
|
||||||
|
(** Substitution commutes with opening under certain conditions. This
|
||||||
|
lemma depends on the fact that opening a locally closed term is
|
||||||
|
the identity. *)
|
||||||
|
|
||||||
|
Lemma subst_tt_open_tt_rec : forall T1 T2 X P k,
|
||||||
|
type P ->
|
||||||
|
subst_tt X P (open_tt_rec k T2 T1) =
|
||||||
|
open_tt_rec k (subst_tt X P T2) (subst_tt X P T1).
|
||||||
|
Proof with auto*.
|
||||||
|
intros T1 T2 X P k WP. revert k.
|
||||||
|
induction T1; intros k; simpl; f_equal...
|
||||||
|
Case "typ_bvar".
|
||||||
|
destruct (k === n); subst...
|
||||||
|
Case "typ_fvar".
|
||||||
|
destruct (a == X); subst... apply open_tt_rec_type...
|
||||||
|
Qed.
|
||||||
|
|
||||||
|
(** The next lemma is a direct corollary of the immediately preceding
|
||||||
|
lemma---the index is specialized to zero. *)
|
||||||
|
|
||||||
|
Lemma subst_tt_open_tt : forall T1 T2 (X:atom) P,
|
||||||
|
type P ->
|
||||||
|
subst_tt X P (open_tt T1 T2) = open_tt (subst_tt X P T1) (subst_tt X P T2).
|
||||||
|
Proof with auto*.
|
||||||
|
intros.
|
||||||
|
unfold open_tt.
|
||||||
|
apply subst_tt_open_tt_rec...
|
||||||
|
Qed.
|
||||||
|
|
||||||
|
(** The next lemma is a direct corollary of the immediately preceding
|
||||||
|
lemma---here, we're opening the term with a variable. In
|
||||||
|
practice, this lemma seems to be needed as a left-to-right rewrite
|
||||||
|
rule, when stated in its current form. *)
|
||||||
|
|
||||||
|
Lemma subst_tt_open_tt_var : forall (X Y:atom) P T,
|
||||||
|
Y <> X ->
|
||||||
|
type P ->
|
||||||
|
open_tt (subst_tt X P T) Y = subst_tt X P (open_tt T Y).
|
||||||
|
Proof with auto*.
|
||||||
|
intros X Y P T Neq Wu.
|
||||||
|
unfold open_tt.
|
||||||
|
rewrite subst_tt_open_tt_rec...
|
||||||
|
simpl.
|
||||||
|
destruct (Y == X)...
|
||||||
|
Qed.
|
||||||
|
|
||||||
|
(** The next lemma states that opening a term is equivalent to first
|
||||||
|
opening the term with a fresh name and then substituting for the
|
||||||
|
name. This is actually the strengthened induction hypothesis for
|
||||||
|
the version we use in practice. *)
|
||||||
|
|
||||||
|
Lemma subst_tt_intro_rec : forall X T2 U k,
|
||||||
|
X `notin` fv_tt T2 ->
|
||||||
|
open_tt_rec k U T2 = subst_tt X U (open_tt_rec k (typ_fvar X) T2).
|
||||||
|
Proof with auto*.
|
||||||
|
induction T2; intros U k Fr; simpl in *; f_equal...
|
||||||
|
Case "typ_bvar".
|
||||||
|
destruct (k === n)... simpl. destruct (X == X)...
|
||||||
|
Case "typ_fvar".
|
||||||
|
destruct (a == X)... absurd_hyp Fr; fsetdec.
|
||||||
|
Qed.
|
||||||
|
|
||||||
|
(** The next lemma is a direct corollary of the immediately preceding
|
||||||
|
lemma---the index is specialized to zero. *)
|
||||||
|
|
||||||
|
Lemma subst_tt_intro : forall X T2 U,
|
||||||
|
X `notin` fv_tt T2 ->
|
||||||
|
open_tt T2 U = subst_tt X U (open_tt T2 X).
|
||||||
|
Proof with auto*.
|
||||||
|
intros.
|
||||||
|
unfold open_tt.
|
||||||
|
apply subst_tt_intro_rec...
|
||||||
|
Qed.
|
||||||
|
|
||||||
|
|
||||||
|
(* ********************************************************************** *)
|
||||||
|
(** ** Properties of type substitution in expressions *)
|
||||||
|
|
||||||
|
(** This section follows the structure of the previous section. The
|
||||||
|
one notable difference is that we require two auxiliary lemmas to
|
||||||
|
show that substituting a type in a locally-closed expression is
|
||||||
|
the identity. *)
|
||||||
|
|
||||||
|
Lemma open_te_rec_expr_aux : forall e j u i P ,
|
||||||
|
open_ee_rec j u e = open_te_rec i P (open_ee_rec j u e) ->
|
||||||
|
e = open_te_rec i P e.
|
||||||
|
Proof with eauto*.
|
||||||
|
induction e; intros j u i P H; simpl in *; inversion H; f_equal...
|
||||||
|
Qed.
|
||||||
|
|
||||||
|
Lemma open_te_rec_type_aux : forall e j Q i P,
|
||||||
|
i <> j ->
|
||||||
|
open_te_rec j Q e = open_te_rec i P (open_te_rec j Q e) ->
|
||||||
|
e = open_te_rec i P e.
|
||||||
|
Proof.
|
||||||
|
induction e; intros j Q i P Neq Heq; simpl in *; inversion Heq;
|
||||||
|
f_equal; eauto using open_tt_rec_type_aux.
|
||||||
|
Qed.
|
||||||
|
|
||||||
|
Lemma open_te_rec_expr : forall e U k,
|
||||||
|
expr e ->
|
||||||
|
e = open_te_rec k U e.
|
||||||
|
Proof with auto*.
|
||||||
|
intros e U k WF. revert k.
|
||||||
|
induction WF; intros k; simpl; f_equal; auto using open_tt_rec_type;
|
||||||
|
try solve [
|
||||||
|
unfold open_ee in *;
|
||||||
|
pick fresh x;
|
||||||
|
eapply open_te_rec_expr_aux with (j := 0) (u := exp_fvar x);
|
||||||
|
auto*
|
||||||
|
| unfold open_te in *;
|
||||||
|
pick fresh X;
|
||||||
|
eapply open_te_rec_type_aux with (j := 0) (Q := typ_fvar X);
|
||||||
|
auto*
|
||||||
|
].
|
||||||
|
Qed.
|
||||||
|
|
||||||
|
Lemma subst_te_fresh : forall X U e,
|
||||||
|
X `notin` fv_te e ->
|
||||||
|
e = subst_te X U e.
|
||||||
|
Proof.
|
||||||
|
induction e; simpl; intros; f_equal; auto using subst_tt_fresh.
|
||||||
|
Qed.
|
||||||
|
|
||||||
|
Lemma subst_te_open_te_rec : forall e T X U k,
|
||||||
|
type U ->
|
||||||
|
subst_te X U (open_te_rec k T e) =
|
||||||
|
open_te_rec k (subst_tt X U T) (subst_te X U e).
|
||||||
|
Proof.
|
||||||
|
intros e T X U k WU. revert k.
|
||||||
|
induction e; intros k; simpl; f_equal; auto using subst_tt_open_tt_rec.
|
||||||
|
Qed.
|
||||||
|
|
||||||
|
Lemma subst_te_open_te : forall e T X U,
|
||||||
|
type U ->
|
||||||
|
subst_te X U (open_te e T) = open_te (subst_te X U e) (subst_tt X U T).
|
||||||
|
Proof with auto*.
|
||||||
|
intros.
|
||||||
|
unfold open_te.
|
||||||
|
apply subst_te_open_te_rec...
|
||||||
|
Qed.
|
||||||
|
|
||||||
|
Lemma subst_te_open_te_var : forall (X Y:atom) U e,
|
||||||
|
Y <> X ->
|
||||||
|
type U ->
|
||||||
|
open_te (subst_te X U e) Y = subst_te X U (open_te e Y).
|
||||||
|
Proof with auto*.
|
||||||
|
intros X Y U e Neq WU.
|
||||||
|
unfold open_te.
|
||||||
|
rewrite subst_te_open_te_rec...
|
||||||
|
simpl.
|
||||||
|
destruct (Y == X)...
|
||||||
|
Qed.
|
||||||
|
|
||||||
|
Lemma subst_te_intro_rec : forall X e U k,
|
||||||
|
X `notin` fv_te e ->
|
||||||
|
open_te_rec k U e = subst_te X U (open_te_rec k (typ_fvar X) e).
|
||||||
|
Proof.
|
||||||
|
induction e; intros U k Fr; simpl in *; f_equal;
|
||||||
|
auto using subst_tt_intro_rec.
|
||||||
|
Qed.
|
||||||
|
|
||||||
|
Lemma subst_te_intro : forall X e U,
|
||||||
|
X `notin` fv_te e ->
|
||||||
|
open_te e U = subst_te X U (open_te e X).
|
||||||
|
Proof with auto*.
|
||||||
|
intros.
|
||||||
|
unfold open_te.
|
||||||
|
apply subst_te_intro_rec...
|
||||||
|
Qed.
|
||||||
|
|
||||||
|
|
||||||
|
(* ********************************************************************** *)
|
||||||
|
(** ** Properties of expression substitution in expressions *)
|
||||||
|
|
||||||
|
(** This section follows the structure of the previous two sections. *)
|
||||||
|
|
||||||
|
Lemma open_ee_rec_expr_aux : forall e j v u i,
|
||||||
|
i <> j ->
|
||||||
|
open_ee_rec j v e = open_ee_rec i u (open_ee_rec j v e) ->
|
||||||
|
e = open_ee_rec i u e.
|
||||||
|
Proof with eauto*.
|
||||||
|
induction e; intros j v u i Neq H; simpl in *; inversion H; f_equal...
|
||||||
|
Case "exp_bvar".
|
||||||
|
destruct (j===n)... destruct (i===n)...
|
||||||
|
Qed.
|
||||||
|
|
||||||
|
Lemma open_ee_rec_type_aux : forall e j V u i,
|
||||||
|
open_te_rec j V e = open_ee_rec i u (open_te_rec j V e) ->
|
||||||
|
e = open_ee_rec i u e.
|
||||||
|
Proof.
|
||||||
|
induction e; intros j V u i H; simpl; inversion H; f_equal; eauto.
|
||||||
|
Qed.
|
||||||
|
|
||||||
|
Lemma open_ee_rec_expr : forall u e k,
|
||||||
|
expr e ->
|
||||||
|
e = open_ee_rec k u e.
|
||||||
|
Proof with auto*.
|
||||||
|
intros u e k Hexpr. revert k.
|
||||||
|
induction Hexpr; intro k; simpl; f_equal; auto*;
|
||||||
|
try solve [
|
||||||
|
unfold open_ee in *;
|
||||||
|
pick fresh x;
|
||||||
|
eapply open_ee_rec_expr_aux with (j := 0) (v := exp_fvar x);
|
||||||
|
auto*
|
||||||
|
| unfold open_te in *;
|
||||||
|
pick fresh X;
|
||||||
|
eapply open_ee_rec_type_aux with (j := 0) (V := typ_fvar X);
|
||||||
|
auto*
|
||||||
|
].
|
||||||
|
Qed.
|
||||||
|
|
||||||
|
Lemma subst_ee_fresh : forall (x: atom) u e,
|
||||||
|
x `notin` fv_ee e ->
|
||||||
|
e = subst_ee x u e.
|
||||||
|
Proof with auto*.
|
||||||
|
intros x u e; induction e; simpl; intro H; f_equal...
|
||||||
|
Case "exp_fvar".
|
||||||
|
destruct (a==x)...
|
||||||
|
absurd_hyp H; fsetdec.
|
||||||
|
Qed.
|
||||||
|
|
||||||
|
Lemma subst_ee_open_ee_rec : forall e1 e2 x u k,
|
||||||
|
expr u ->
|
||||||
|
subst_ee x u (open_ee_rec k e2 e1) =
|
||||||
|
open_ee_rec k (subst_ee x u e2) (subst_ee x u e1).
|
||||||
|
Proof with auto*.
|
||||||
|
intros e1 e2 x u k WP. revert k.
|
||||||
|
induction e1; intros k; simpl; f_equal...
|
||||||
|
Case "exp_bvar".
|
||||||
|
destruct (k === n); subst...
|
||||||
|
Case "exp_fvar".
|
||||||
|
destruct (a == x); subst... apply open_ee_rec_expr...
|
||||||
|
Qed.
|
||||||
|
|
||||||
|
Lemma subst_ee_open_ee : forall e1 e2 x u,
|
||||||
|
expr u ->
|
||||||
|
subst_ee x u (open_ee e1 e2) =
|
||||||
|
open_ee (subst_ee x u e1) (subst_ee x u e2).
|
||||||
|
Proof with auto*.
|
||||||
|
intros.
|
||||||
|
unfold open_ee.
|
||||||
|
apply subst_ee_open_ee_rec...
|
||||||
|
Qed.
|
||||||
|
|
||||||
|
Lemma subst_ee_open_ee_var : forall (x y:atom) u e,
|
||||||
|
y <> x ->
|
||||||
|
expr u ->
|
||||||
|
open_ee (subst_ee x u e) y = subst_ee x u (open_ee e y).
|
||||||
|
Proof with auto*.
|
||||||
|
intros x y u e Neq Wu.
|
||||||
|
unfold open_ee.
|
||||||
|
rewrite subst_ee_open_ee_rec...
|
||||||
|
simpl.
|
||||||
|
destruct (y == x)...
|
||||||
|
Qed.
|
||||||
|
|
||||||
|
Lemma subst_te_open_ee_rec : forall e1 e2 Z P k,
|
||||||
|
subst_te Z P (open_ee_rec k e2 e1) =
|
||||||
|
open_ee_rec k (subst_te Z P e2) (subst_te Z P e1).
|
||||||
|
Proof with auto*.
|
||||||
|
induction e1; intros e2 Z P k; simpl; f_equal...
|
||||||
|
Case "exp_bvar".
|
||||||
|
destruct (k === n)...
|
||||||
|
Qed.
|
||||||
|
|
||||||
|
Lemma subst_te_open_ee : forall e1 e2 Z P,
|
||||||
|
subst_te Z P (open_ee e1 e2) = open_ee (subst_te Z P e1) (subst_te Z P e2).
|
||||||
|
Proof with auto*.
|
||||||
|
intros.
|
||||||
|
unfold open_ee.
|
||||||
|
apply subst_te_open_ee_rec...
|
||||||
|
Qed.
|
||||||
|
|
||||||
|
Lemma subst_te_open_ee_var : forall Z (x:atom) P e,
|
||||||
|
open_ee (subst_te Z P e) x = subst_te Z P (open_ee e x).
|
||||||
|
Proof with auto*.
|
||||||
|
intros.
|
||||||
|
rewrite subst_te_open_ee...
|
||||||
|
Qed.
|
||||||
|
|
||||||
|
Lemma subst_ee_open_te_rec : forall e P z u k,
|
||||||
|
expr u ->
|
||||||
|
subst_ee z u (open_te_rec k P e) = open_te_rec k P (subst_ee z u e).
|
||||||
|
Proof with auto*.
|
||||||
|
induction e; intros P z u k H; simpl; f_equal...
|
||||||
|
Case "exp_fvar".
|
||||||
|
destruct (a == z)... apply open_te_rec_expr...
|
||||||
|
Qed.
|
||||||
|
|
||||||
|
Lemma subst_ee_open_te : forall e P z u,
|
||||||
|
expr u ->
|
||||||
|
subst_ee z u (open_te e P) = open_te (subst_ee z u e) P.
|
||||||
|
Proof with auto*.
|
||||||
|
intros.
|
||||||
|
unfold open_te.
|
||||||
|
apply subst_ee_open_te_rec...
|
||||||
|
Qed.
|
||||||
|
|
||||||
|
Lemma subst_ee_open_te_var : forall z (X:atom) u e,
|
||||||
|
expr u ->
|
||||||
|
open_te (subst_ee z u e) X = subst_ee z u (open_te e X).
|
||||||
|
Proof with auto*.
|
||||||
|
intros z X u e H.
|
||||||
|
rewrite subst_ee_open_te...
|
||||||
|
Qed.
|
||||||
|
|
||||||
|
Lemma subst_ee_intro_rec : forall x e u k,
|
||||||
|
x `notin` fv_ee e ->
|
||||||
|
open_ee_rec k u e = subst_ee x u (open_ee_rec k (exp_fvar x) e).
|
||||||
|
Proof with auto*.
|
||||||
|
induction e; intros u k Fr; simpl in *; f_equal...
|
||||||
|
Case "exp_bvar".
|
||||||
|
destruct (k === n)... simpl. destruct (x == x)...
|
||||||
|
Case "exp_fvar".
|
||||||
|
destruct (a == x)... absurd_hyp Fr; fsetdec.
|
||||||
|
Qed.
|
||||||
|
|
||||||
|
Lemma subst_ee_intro : forall x e u,
|
||||||
|
x `notin` fv_ee e ->
|
||||||
|
open_ee e u = subst_ee x u (open_ee e x).
|
||||||
|
Proof with auto*.
|
||||||
|
intros.
|
||||||
|
unfold open_ee.
|
||||||
|
apply subst_ee_intro_rec...
|
||||||
|
Qed.
|
||||||
|
|
||||||
|
|
||||||
|
(* *********************************************************************** *)
|
||||||
|
(** * #<a name="lc"></a># Local closure is preserved under substitution *)
|
||||||
|
|
||||||
|
(** While these lemmas may be considered properties of substitution, we
|
||||||
|
separate them out due to the lemmas that they depend on. *)
|
||||||
|
|
||||||
|
(** The following lemma depends on [subst_tt_open_tt_var]. *)
|
||||||
|
|
||||||
|
Lemma subst_tt_type : forall Z P T,
|
||||||
|
type T ->
|
||||||
|
type P ->
|
||||||
|
type (subst_tt Z P T).
|
||||||
|
Proof with auto.
|
||||||
|
intros Z P T HT HP.
|
||||||
|
induction HT; simpl...
|
||||||
|
Case "type_fvar".
|
||||||
|
destruct (X == Z)...
|
||||||
|
Case "type_all".
|
||||||
|
pick fresh Y and apply type_all...
|
||||||
|
rewrite subst_tt_open_tt_var...
|
||||||
|
Qed.
|
||||||
|
|
||||||
|
(** The following lemma depends on [subst_tt_type] and
|
||||||
|
[subst_te_open_ee_var]. *)
|
||||||
|
|
||||||
|
Lemma subst_te_expr : forall Z P e,
|
||||||
|
expr e ->
|
||||||
|
type P ->
|
||||||
|
expr (subst_te Z P e).
|
||||||
|
Proof with eauto using subst_tt_type.
|
||||||
|
intros Z P e He Hp.
|
||||||
|
induction He; simpl; auto using subst_tt_type;
|
||||||
|
try solve [
|
||||||
|
econstructor;
|
||||||
|
try instantiate (1 := L `union` singleton Z);
|
||||||
|
intros;
|
||||||
|
try rewrite subst_te_open_ee_var;
|
||||||
|
try rewrite subst_te_open_te_var;
|
||||||
|
eauto using subst_tt_type
|
||||||
|
].
|
||||||
|
Qed.
|
||||||
|
|
||||||
|
(** The following lemma depends on [subst_ee_open_ee_var] and
|
||||||
|
[subst_ee_open_te_var]. *)
|
||||||
|
|
||||||
|
Lemma subst_ee_expr : forall z e1 e2,
|
||||||
|
expr e1 ->
|
||||||
|
expr e2 ->
|
||||||
|
expr (subst_ee z e2 e1).
|
||||||
|
Proof with auto.
|
||||||
|
intros z e1 e2 He1 He2.
|
||||||
|
induction He1; simpl; auto;
|
||||||
|
try solve [
|
||||||
|
econstructor;
|
||||||
|
try instantiate (1 := L `union` singleton z);
|
||||||
|
intros;
|
||||||
|
try rewrite subst_ee_open_ee_var;
|
||||||
|
try rewrite subst_ee_open_te_var;
|
||||||
|
auto
|
||||||
|
].
|
||||||
|
Case "expr_var".
|
||||||
|
destruct (x == z)...
|
||||||
|
Qed.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
(* *********************************************************************** *)
|
||||||
|
(** * #<a name="auto"></a># Automation *)
|
||||||
|
|
||||||
|
(** We add as hints the fact that local closure is preserved under
|
||||||
|
substitution. This is part of our strategy for automatically
|
||||||
|
discharging local-closure proof obligations. *)
|
||||||
|
|
||||||
|
Hint Resolve subst_tt_type subst_te_expr subst_ee_expr.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
(** When reasoning about the [binds] relation and [map], we
|
||||||
|
occasionally encounter situations where the binding is
|
||||||
|
over-simplified. The following hint undoes that simplification,
|
||||||
|
thus enabling [Hint]s from the [Environment] library. *)
|
||||||
|
|
||||||
|
Hint Extern 1 (binds _ (?F (subst_tt ?X ?U ?T)) _) =>
|
||||||
|
unsimpl (subst_tb X U (F T)).
|
399
coq-Fsub/Fsub_Lemmas.v
Normal file
399
coq-Fsub/Fsub_Lemmas.v
Normal file
|
@ -0,0 +1,399 @@
|
||||||
|
(** Administrative lemmas for Fsub.
|
||||||
|
|
||||||
|
Authors: Brian Aydemir and Arthur Charguéraud, with help from
|
||||||
|
Aaron Bohannon, Jeffrey Vaughan, and Dimitrios Vytiniotis.
|
||||||
|
|
||||||
|
This file contains a number of administrative lemmas that we
|
||||||
|
require for proving type-safety. The lemmas mainly concern the
|
||||||
|
relations [wf_typ] and [wf_env].
|
||||||
|
|
||||||
|
This file also contains regularity lemmas, which show that various
|
||||||
|
relations hold only for locally closed terms. In addition to
|
||||||
|
being necessary to complete the proof of type-safety, these lemmas
|
||||||
|
help demonstrate that our definitions are correct; they would be
|
||||||
|
worth proving even if they are unneeded for any "real" proofs.
|
||||||
|
|
||||||
|
Table of contents:
|
||||||
|
- #<a href="##wft">Properties of wf_typ</a>#
|
||||||
|
- #<a href="##oktwft">Properties of wf_env and wf_typ</a>#
|
||||||
|
- #<a href="##okt">Properties of wf_env</a>#
|
||||||
|
- #<a href="##subst">Properties of substitution</a>#
|
||||||
|
- #<a href="##regularity">Regularity lemmas</a>#
|
||||||
|
- #<a href="##auto">Automation</a># *)
|
||||||
|
|
||||||
|
Require Export Fsub_Infrastructure.
|
||||||
|
|
||||||
|
|
||||||
|
(* ********************************************************************** *)
|
||||||
|
(** * #<a name="wft"></a># Properties of [wf_typ] *)
|
||||||
|
|
||||||
|
(** If a type is well-formed in an environment, then it is locally
|
||||||
|
closed. *)
|
||||||
|
|
||||||
|
Lemma type_from_wf_typ : forall E T,
|
||||||
|
wf_typ E T -> type T.
|
||||||
|
Proof.
|
||||||
|
intros E T H; induction H; eauto.
|
||||||
|
Qed.
|
||||||
|
|
||||||
|
(** The remaining properties are analogous to the properties that we
|
||||||
|
need to show for the subtyping and typing relations. *)
|
||||||
|
|
||||||
|
Lemma wf_typ_weakening : forall T E F G,
|
||||||
|
wf_typ (G ++ E) T ->
|
||||||
|
ok (G ++ F ++ E) ->
|
||||||
|
wf_typ (G ++ F ++ E) T.
|
||||||
|
Proof with simpl_env; eauto.
|
||||||
|
intros T E F G Hwf_typ Hk.
|
||||||
|
remember (G ++ E) as F.
|
||||||
|
generalize dependent G.
|
||||||
|
induction Hwf_typ; intros G Hok Heq; subst...
|
||||||
|
Case "type_all".
|
||||||
|
pick fresh Y and apply wf_typ_all...
|
||||||
|
rewrite <- concat_assoc.
|
||||||
|
apply H0...
|
||||||
|
Qed.
|
||||||
|
|
||||||
|
Lemma wf_typ_weaken_head : forall T E F,
|
||||||
|
wf_typ E T ->
|
||||||
|
ok (F ++ E) ->
|
||||||
|
wf_typ (F ++ E) T.
|
||||||
|
Proof.
|
||||||
|
intros.
|
||||||
|
rewrite_env (empty ++ F++ E).
|
||||||
|
auto using wf_typ_weakening.
|
||||||
|
Qed.
|
||||||
|
|
||||||
|
Lemma wf_typ_narrowing : forall V U T E F X,
|
||||||
|
wf_typ (F ++ [(X, bind_sub V)] ++ E) T ->
|
||||||
|
ok (F ++ [(X, bind_sub U)] ++ E) ->
|
||||||
|
wf_typ (F ++ [(X, bind_sub U)] ++ E) T.
|
||||||
|
Proof with simpl_env; eauto.
|
||||||
|
intros V U T E F X Hwf_typ Hok.
|
||||||
|
remember (F ++ [(X, bind_sub V)] ++ E) as G.
|
||||||
|
generalize dependent F.
|
||||||
|
induction Hwf_typ; intros F Hok Heq; subst...
|
||||||
|
Case "wf_typ_var".
|
||||||
|
binds_cases H...
|
||||||
|
Case "typ_all".
|
||||||
|
pick fresh Y and apply wf_typ_all...
|
||||||
|
rewrite <- concat_assoc.
|
||||||
|
apply H0...
|
||||||
|
Qed.
|
||||||
|
|
||||||
|
Lemma wf_typ_strengthening : forall E F x U T,
|
||||||
|
wf_typ (F ++ [(x, bind_typ U)] ++ E) T ->
|
||||||
|
wf_typ (F ++ E) T.
|
||||||
|
Proof with simpl_env; eauto.
|
||||||
|
intros E F x U T H.
|
||||||
|
remember (F ++ [(x, bind_typ U)] ++ E) as G.
|
||||||
|
generalize dependent F.
|
||||||
|
induction H; intros F Heq; subst...
|
||||||
|
Case "wf_typ_var".
|
||||||
|
binds_cases H...
|
||||||
|
Case "wf_typ_all".
|
||||||
|
pick fresh Y and apply wf_typ_all...
|
||||||
|
rewrite <- concat_assoc.
|
||||||
|
apply H1...
|
||||||
|
Qed.
|
||||||
|
|
||||||
|
Lemma wf_typ_subst_tb : forall F Q E Z P T,
|
||||||
|
wf_typ (F ++ [(Z, bind_sub Q)] ++ E) T ->
|
||||||
|
wf_typ E P ->
|
||||||
|
ok (map (subst_tb Z P) F ++ E) ->
|
||||||
|
wf_typ (map (subst_tb Z P) F ++ E) (subst_tt Z P T).
|
||||||
|
Proof with simpl_env; eauto using wf_typ_weaken_head, type_from_wf_typ.
|
||||||
|
intros F Q E Z P T WT WP.
|
||||||
|
remember (F ++ [(Z, bind_sub Q)] ++ E) as G.
|
||||||
|
generalize dependent F.
|
||||||
|
induction WT; intros F EQ Ok; subst; simpl subst_tt...
|
||||||
|
Case "wf_typ_var".
|
||||||
|
destruct (X == Z); subst...
|
||||||
|
SCase "X <> Z".
|
||||||
|
binds_cases H...
|
||||||
|
apply (wf_typ_var (subst_tt Z P U))...
|
||||||
|
Case "wf_typ_all".
|
||||||
|
pick fresh Y and apply wf_typ_all...
|
||||||
|
rewrite subst_tt_open_tt_var...
|
||||||
|
rewrite_env (map (subst_tb Z P) ([(Y, bind_sub T1)] ++ F) ++ E).
|
||||||
|
apply H0...
|
||||||
|
Qed.
|
||||||
|
|
||||||
|
Lemma wf_typ_open : forall E U T1 T2,
|
||||||
|
ok E ->
|
||||||
|
wf_typ E (typ_all T1 T2) ->
|
||||||
|
wf_typ E U ->
|
||||||
|
wf_typ E (open_tt T2 U).
|
||||||
|
Proof with simpl_env; eauto.
|
||||||
|
intros E U T1 T2 Ok WA WU.
|
||||||
|
inversion WA; subst.
|
||||||
|
pick fresh X.
|
||||||
|
rewrite (subst_tt_intro X)...
|
||||||
|
rewrite_env (map (subst_tb X U) empty ++ E).
|
||||||
|
eapply wf_typ_subst_tb...
|
||||||
|
Qed.
|
||||||
|
|
||||||
|
|
||||||
|
(* ********************************************************************** *)
|
||||||
|
(** * #<a name="oktwft"></a># Properties of [wf_env] and [wf_typ] *)
|
||||||
|
|
||||||
|
Lemma ok_from_wf_env : forall E,
|
||||||
|
wf_env E ->
|
||||||
|
ok E.
|
||||||
|
Proof.
|
||||||
|
intros E H; induction H; auto.
|
||||||
|
Qed.
|
||||||
|
|
||||||
|
(** We add [ok_from_wf_env] as a hint here since it helps blur the
|
||||||
|
distinction between [wf_env] and [ok] in proofs. The lemmas in
|
||||||
|
the [Environment] library use [ok], whereas here we naturally have
|
||||||
|
(or can easily show) the stronger [wf_env]. Thus,
|
||||||
|
[ok_from_wf_env] serves as a bridge that allows us to use the
|
||||||
|
environments library. *)
|
||||||
|
|
||||||
|
Hint Resolve ok_from_wf_env.
|
||||||
|
|
||||||
|
Lemma wf_typ_from_binds_typ : forall x U E,
|
||||||
|
wf_env E ->
|
||||||
|
binds x (bind_typ U) E ->
|
||||||
|
wf_typ E U.
|
||||||
|
Proof with auto using wf_typ_weaken_head.
|
||||||
|
induction 1; intros J; binds_cases J...
|
||||||
|
inversion H4; subst...
|
||||||
|
Qed.
|
||||||
|
|
||||||
|
Lemma wf_typ_from_wf_env_typ : forall x T E,
|
||||||
|
wf_env ([(x, bind_typ T)] ++ E) ->
|
||||||
|
wf_typ E T.
|
||||||
|
Proof.
|
||||||
|
intros x T E H. inversion H; auto.
|
||||||
|
Qed.
|
||||||
|
|
||||||
|
Lemma wf_typ_from_wf_env_sub : forall x T E,
|
||||||
|
wf_env ([(x, bind_sub T)] ++ E) ->
|
||||||
|
wf_typ E T.
|
||||||
|
Proof.
|
||||||
|
intros x T E H. inversion H; auto.
|
||||||
|
Qed.
|
||||||
|
|
||||||
|
|
||||||
|
(* ********************************************************************** *)
|
||||||
|
(** * #<a name="okt"></a># Properties of [wf_env] *)
|
||||||
|
|
||||||
|
(** These properties are analogous to the properties that we need to
|
||||||
|
show for the subtyping and typing relations. *)
|
||||||
|
|
||||||
|
Lemma wf_env_narrowing : forall V E F U X,
|
||||||
|
wf_env (F ++ [(X, bind_sub V)] ++ E) ->
|
||||||
|
wf_typ E U ->
|
||||||
|
wf_env (F ++ [(X, bind_sub U)] ++ E).
|
||||||
|
Proof with eauto 6 using wf_typ_narrowing.
|
||||||
|
induction F; intros U X Wf_env Wf;
|
||||||
|
inversion Wf_env; subst; simpl_env in *...
|
||||||
|
Qed.
|
||||||
|
|
||||||
|
Lemma wf_env_strengthening : forall x T E F,
|
||||||
|
wf_env (F ++ [(x, bind_typ T)] ++ E) ->
|
||||||
|
wf_env (F ++ E).
|
||||||
|
Proof with eauto using wf_typ_strengthening.
|
||||||
|
induction F; intros Wf_env; inversion Wf_env; subst; simpl_env in *...
|
||||||
|
Qed.
|
||||||
|
|
||||||
|
Lemma wf_env_subst_tb : forall Q Z P E F,
|
||||||
|
wf_env (F ++ [(Z, bind_sub Q)] ++ E) ->
|
||||||
|
wf_typ E P ->
|
||||||
|
wf_env (map (subst_tb Z P) F ++ E).
|
||||||
|
Proof with eauto 6 using wf_typ_subst_tb.
|
||||||
|
induction F; intros Wf_env WP; simpl_env;
|
||||||
|
inversion Wf_env; simpl_env in *; simpl subst_tb...
|
||||||
|
Qed.
|
||||||
|
|
||||||
|
|
||||||
|
(* ********************************************************************** *)
|
||||||
|
(** * #<a name="subst"></a># Environment is unchanged by substitution for a fresh name *)
|
||||||
|
|
||||||
|
Lemma notin_fv_tt_open : forall (Y X : atom) T,
|
||||||
|
X `notin` fv_tt (open_tt T Y) ->
|
||||||
|
X `notin` fv_tt T.
|
||||||
|
Proof.
|
||||||
|
intros Y X T. unfold open_tt.
|
||||||
|
generalize 0.
|
||||||
|
induction T; simpl; intros k Fr; notin_simpl; try apply notin_union; eauto.
|
||||||
|
Qed.
|
||||||
|
|
||||||
|
Lemma notin_fv_wf : forall E (X : atom) T,
|
||||||
|
wf_typ E T ->
|
||||||
|
X `notin` dom E ->
|
||||||
|
X `notin` fv_tt T.
|
||||||
|
Proof with auto.
|
||||||
|
intros E X T Wf_typ.
|
||||||
|
induction Wf_typ; intros Fr; simpl...
|
||||||
|
Case "wf_typ_var".
|
||||||
|
assert (X0 `in` (dom E))...
|
||||||
|
eapply binds_In; eauto.
|
||||||
|
Case "wf_typ_all".
|
||||||
|
apply notin_union...
|
||||||
|
pick fresh Y.
|
||||||
|
apply (notin_fv_tt_open Y)...
|
||||||
|
Qed.
|
||||||
|
|
||||||
|
Lemma map_subst_tb_id : forall G Z P,
|
||||||
|
wf_env G ->
|
||||||
|
Z `notin` dom G ->
|
||||||
|
G = map (subst_tb Z P) G.
|
||||||
|
Proof with auto.
|
||||||
|
intros G Z P H.
|
||||||
|
induction H; simpl; intros Fr; simpl_env...
|
||||||
|
rewrite <- IHwf_env...
|
||||||
|
rewrite <- subst_tt_fresh... eapply notin_fv_wf; eauto.
|
||||||
|
rewrite <- IHwf_env...
|
||||||
|
rewrite <- subst_tt_fresh... eapply notin_fv_wf; eauto.
|
||||||
|
Qed.
|
||||||
|
|
||||||
|
|
||||||
|
(* ********************************************************************** *)
|
||||||
|
(** * #<a name="regularity"></a># Regularity of relations *)
|
||||||
|
|
||||||
|
Lemma sub_regular : forall E S T,
|
||||||
|
sub E S T ->
|
||||||
|
wf_env E /\ wf_typ E S /\ wf_typ E T.
|
||||||
|
Proof with simpl_env; auto*.
|
||||||
|
intros E S T H.
|
||||||
|
induction H...
|
||||||
|
Case "sub_trans_tvar".
|
||||||
|
eauto*.
|
||||||
|
Case "sub_all".
|
||||||
|
repeat split...
|
||||||
|
SCase "Second of original three conjuncts".
|
||||||
|
pick fresh Y and apply wf_typ_all...
|
||||||
|
destruct (H1 Y)...
|
||||||
|
rewrite_env (empty ++ [(Y, bind_sub S1)] ++ E).
|
||||||
|
apply (wf_typ_narrowing T1)...
|
||||||
|
SCase "Third of original three conjuncts".
|
||||||
|
pick fresh Y and apply wf_typ_all...
|
||||||
|
destruct (H1 Y)...
|
||||||
|
Qed.
|
||||||
|
|
||||||
|
Lemma typing_regular : forall E e T,
|
||||||
|
typing E e T ->
|
||||||
|
wf_env E /\ expr e /\ wf_typ E T.
|
||||||
|
Proof with simpl_env; auto*.
|
||||||
|
intros E e T H; induction H...
|
||||||
|
Case "typing_var".
|
||||||
|
repeat split...
|
||||||
|
eauto using wf_typ_from_binds_typ.
|
||||||
|
Case "typing_abs".
|
||||||
|
pick fresh y.
|
||||||
|
destruct (H0 y) as [Hok [J K]]...
|
||||||
|
repeat split. inversion Hok...
|
||||||
|
SCase "Second of original three conjuncts".
|
||||||
|
pick fresh x and apply expr_abs.
|
||||||
|
eauto using type_from_wf_typ, wf_typ_from_wf_env_typ.
|
||||||
|
destruct (H0 x)...
|
||||||
|
SCase "Third of original three conjuncts".
|
||||||
|
apply wf_typ_arrow; eauto using wf_typ_from_wf_env_typ.
|
||||||
|
rewrite_env (empty ++ E).
|
||||||
|
eapply wf_typ_strengthening; simpl_env; eauto.
|
||||||
|
Case "typing_app".
|
||||||
|
repeat split...
|
||||||
|
destruct IHtyping1 as [_ [_ K]].
|
||||||
|
inversion K...
|
||||||
|
Case "typing_tabs".
|
||||||
|
pick fresh Y.
|
||||||
|
destruct (H0 Y) as [Hok [J K]]...
|
||||||
|
inversion Hok; subst.
|
||||||
|
repeat split...
|
||||||
|
SCase "Second of original three conjuncts".
|
||||||
|
pick fresh X and apply expr_tabs.
|
||||||
|
eauto using type_from_wf_typ, wf_typ_from_wf_env_sub...
|
||||||
|
destruct (H0 X)...
|
||||||
|
SCase "Third of original three conjuncts".
|
||||||
|
pick fresh Z and apply wf_typ_all...
|
||||||
|
destruct (H0 Z)...
|
||||||
|
Case "typing_tapp".
|
||||||
|
destruct (sub_regular _ _ _ H0) as [R1 [R2 R3]].
|
||||||
|
repeat split...
|
||||||
|
SCase "Second of original three conjuncts".
|
||||||
|
apply expr_tapp...
|
||||||
|
eauto using type_from_wf_typ.
|
||||||
|
SCase "Third of original three conjuncts".
|
||||||
|
destruct IHtyping as [R1' [R2' R3']].
|
||||||
|
eapply wf_typ_open; eauto.
|
||||||
|
Case "typing_sub".
|
||||||
|
repeat split...
|
||||||
|
destruct (sub_regular _ _ _ H0)...
|
||||||
|
Qed.
|
||||||
|
|
||||||
|
Lemma value_regular : forall e,
|
||||||
|
value e ->
|
||||||
|
expr e.
|
||||||
|
Proof.
|
||||||
|
intros e H. induction H; auto.
|
||||||
|
Qed.
|
||||||
|
|
||||||
|
Lemma red_regular : forall e e',
|
||||||
|
red e e' ->
|
||||||
|
expr e /\ expr e'.
|
||||||
|
Proof with auto*.
|
||||||
|
intros e e' H.
|
||||||
|
induction H; assert(J := value_regular); split...
|
||||||
|
Case "red_abs".
|
||||||
|
inversion H. pick fresh y. rewrite (subst_ee_intro y)...
|
||||||
|
Case "red_tabs".
|
||||||
|
inversion H. pick fresh Y. rewrite (subst_te_intro Y)...
|
||||||
|
Qed.
|
||||||
|
|
||||||
|
|
||||||
|
(* *********************************************************************** *)
|
||||||
|
(** * #<a name="auto"></a># Automation *)
|
||||||
|
|
||||||
|
(** The lemma [ok_from_wf_env] was already added above as a hint since it
|
||||||
|
helps blur the distinction between [wf_env] and [ok] in proofs.
|
||||||
|
|
||||||
|
As currently stated, the regularity lemmas are ill-suited to be
|
||||||
|
used with [auto] and [eauto] since they end in conjunctions. Even
|
||||||
|
if we were, for example, to split [sub_regularity] into three
|
||||||
|
separate lemmas, the resulting lemmas would be usable only by
|
||||||
|
[eauto] and there is no guarantee that [eauto] would be able to
|
||||||
|
find proofs effectively. Thus, the hints below apply the
|
||||||
|
regularity lemmas and [type_from_wf_typ] to discharge goals about
|
||||||
|
local closure and well-formedness, but in such a way as to
|
||||||
|
minimize proof search.
|
||||||
|
|
||||||
|
The first hint introduces an [wf_env] fact into the context. It
|
||||||
|
works well when combined with the lemmas relating [wf_env] and
|
||||||
|
[wf_typ]. We choose to use those lemmas explicitly via [(auto
|
||||||
|
using ...)] tactics rather than add them as hints. When used this
|
||||||
|
way, the explicitness makes the proof more informative rather than
|
||||||
|
more cluttered (with useless details).
|
||||||
|
|
||||||
|
The other three hints try outright to solve their respective
|
||||||
|
goals. *)
|
||||||
|
|
||||||
|
Hint Extern 1 (wf_env ?E) =>
|
||||||
|
match goal with
|
||||||
|
| H: sub _ _ _ |- _ => apply (proj1 (sub_regular _ _ _ H))
|
||||||
|
| H: typing _ _ _ |- _ => apply (proj1 (typing_regular _ _ _ H))
|
||||||
|
end.
|
||||||
|
|
||||||
|
Hint Extern 1 (wf_typ ?E ?T) =>
|
||||||
|
match goal with
|
||||||
|
| H: typing E _ T |- _ => apply (proj2 (proj2 (typing_regular _ _ _ H)))
|
||||||
|
| H: sub E T _ |- _ => apply (proj1 (proj2 (sub_regular _ _ _ H)))
|
||||||
|
| H: sub E _ T |- _ => apply (proj2 (proj2 (sub_regular _ _ _ H)))
|
||||||
|
end.
|
||||||
|
|
||||||
|
Hint Extern 1 (type ?T) =>
|
||||||
|
let go E := apply (type_from_wf_typ E); auto in
|
||||||
|
match goal with
|
||||||
|
| H: typing ?E _ T |- _ => go E
|
||||||
|
| H: sub ?E T _ |- _ => go E
|
||||||
|
| H: sub ?E _ T |- _ => go E
|
||||||
|
end.
|
||||||
|
|
||||||
|
Hint Extern 1 (expr ?e) =>
|
||||||
|
match goal with
|
||||||
|
| H: typing _ ?e _ |- _ => apply (proj1 (proj2 (typing_regular _ _ _ H)))
|
||||||
|
| H: red ?e _ |- _ => apply (proj1 (red_regular _ _ H))
|
||||||
|
| H: red _ ?e |- _ => apply (proj2 (red_regular _ _ H))
|
||||||
|
end.
|
593
coq-Fsub/Fsub_Soundness.v
Normal file
593
coq-Fsub/Fsub_Soundness.v
Normal file
|
@ -0,0 +1,593 @@
|
||||||
|
(** Type-safety proofs for Fsub.
|
||||||
|
|
||||||
|
Authors: Brian Aydemir and Arthur Charguéraud, with help from
|
||||||
|
Aaron Bohannon, Jeffrey Vaughan, and Dimitrios Vytiniotis.
|
||||||
|
|
||||||
|
In parentheses are given the label of the corresponding lemma in
|
||||||
|
the appendix (informal proofs) of the POPLmark Challenge.
|
||||||
|
|
||||||
|
Table of contents:
|
||||||
|
- #<a href="##subtyping">Properties of subtyping</a>#
|
||||||
|
- #<a href="##typing">Properties of typing</a>#
|
||||||
|
- #<a href="##preservation">Preservation</a>#
|
||||||
|
- #<a href="##progress">Progress</a># *)
|
||||||
|
|
||||||
|
Require Export Fsub_Lemmas.
|
||||||
|
|
||||||
|
|
||||||
|
(* ********************************************************************** *)
|
||||||
|
(** * #<a name="subtyping"></a># Properties of subtyping *)
|
||||||
|
|
||||||
|
|
||||||
|
(* ********************************************************************** *)
|
||||||
|
(** ** Reflexivity (1) *)
|
||||||
|
|
||||||
|
Lemma sub_reflexivity : forall E T,
|
||||||
|
wf_env E ->
|
||||||
|
wf_typ E T ->
|
||||||
|
sub E T T.
|
||||||
|
Proof with eauto.
|
||||||
|
intros E T Ok Wf.
|
||||||
|
induction Wf...
|
||||||
|
pick fresh Y and apply sub_all...
|
||||||
|
Qed.
|
||||||
|
|
||||||
|
|
||||||
|
(* ********************************************************************** *)
|
||||||
|
(** ** Weakening (2) *)
|
||||||
|
|
||||||
|
Lemma sub_weakening : forall E F G S T,
|
||||||
|
sub (G ++ E) S T ->
|
||||||
|
wf_env (G ++ F ++ E) ->
|
||||||
|
sub (G ++ F ++ E) S T.
|
||||||
|
Proof with simpl_env; auto using wf_typ_weakening.
|
||||||
|
intros E F G S T Sub Ok.
|
||||||
|
remember (G ++ E) as H.
|
||||||
|
generalize dependent G.
|
||||||
|
induction Sub; intros G Ok EQ; subst...
|
||||||
|
Case "sub_trans_tvar".
|
||||||
|
apply (sub_trans_tvar U)...
|
||||||
|
Case "sub_all".
|
||||||
|
pick fresh Y and apply sub_all...
|
||||||
|
rewrite <- concat_assoc.
|
||||||
|
apply H0...
|
||||||
|
Qed.
|
||||||
|
|
||||||
|
|
||||||
|
(* ********************************************************************** *)
|
||||||
|
(** ** Narrowing and transitivity (3) *)
|
||||||
|
|
||||||
|
Definition transitivity_on Q := forall E S T,
|
||||||
|
sub E S Q -> sub E Q T -> sub E S T.
|
||||||
|
|
||||||
|
Lemma sub_narrowing_aux : forall Q F E Z P S T,
|
||||||
|
transitivity_on Q ->
|
||||||
|
sub (F ++ [(Z, bind_sub Q)] ++ E) S T ->
|
||||||
|
sub E P Q ->
|
||||||
|
sub (F ++ [(Z, bind_sub P)] ++ E) S T.
|
||||||
|
Proof with simpl_env; eauto using wf_typ_narrowing, wf_env_narrowing.
|
||||||
|
intros Q F E Z P S T TransQ SsubT PsubQ.
|
||||||
|
remember (F ++ [(Z, bind_sub Q)] ++ E) as G. generalize dependent F.
|
||||||
|
induction SsubT; intros F EQ; subst...
|
||||||
|
Case "sub_top".
|
||||||
|
apply sub_top...
|
||||||
|
Case "sub_refl_tvar".
|
||||||
|
apply sub_refl_tvar...
|
||||||
|
Case "sub_trans_tvar".
|
||||||
|
destruct (X == Z); subst.
|
||||||
|
SCase "X = Z".
|
||||||
|
apply (sub_trans_tvar P); [ eauto using fresh_mid_head | ].
|
||||||
|
apply TransQ.
|
||||||
|
SSCase "P <: Q".
|
||||||
|
rewrite_env (empty ++ (F ++ [(Z, bind_sub P)]) ++ E).
|
||||||
|
apply sub_weakening...
|
||||||
|
SSCase "Q <: T".
|
||||||
|
binds_get H.
|
||||||
|
inversion H1; subst...
|
||||||
|
SCase "X <> Z".
|
||||||
|
apply (sub_trans_tvar U)...
|
||||||
|
binds_cases H...
|
||||||
|
Case "sub_all".
|
||||||
|
pick fresh Y and apply sub_all...
|
||||||
|
rewrite <- concat_assoc.
|
||||||
|
apply H0...
|
||||||
|
Qed.
|
||||||
|
|
||||||
|
Lemma sub_transitivity : forall Q,
|
||||||
|
transitivity_on Q.
|
||||||
|
Proof with simpl_env; auto.
|
||||||
|
unfold transitivity_on.
|
||||||
|
intros Q E S T SsubQ QsubT.
|
||||||
|
assert (W : type Q) by auto.
|
||||||
|
generalize dependent T.
|
||||||
|
generalize dependent S.
|
||||||
|
generalize dependent E.
|
||||||
|
remember Q as Q' in |-.
|
||||||
|
generalize dependent Q'.
|
||||||
|
induction W;
|
||||||
|
intros Q' EQ E S SsubQ;
|
||||||
|
induction SsubQ; try discriminate; inversion EQ; subst;
|
||||||
|
intros T' QsubT;
|
||||||
|
inversion QsubT; subst; eauto 4 using sub_trans_tvar.
|
||||||
|
Case "sub_all / sub_top".
|
||||||
|
assert (sub E (typ_all S1 S2) (typ_all T1 T2)).
|
||||||
|
SCase "proof of assertion".
|
||||||
|
pick fresh y and apply sub_all...
|
||||||
|
auto.
|
||||||
|
Case "sub_all / sub_all".
|
||||||
|
pick fresh Y and apply sub_all.
|
||||||
|
SCase "bounds".
|
||||||
|
eauto.
|
||||||
|
SCase "bodies".
|
||||||
|
lapply (H0 Y); [ intros K | auto ].
|
||||||
|
apply (K (open_tt T2 Y))...
|
||||||
|
rewrite_env (empty ++ [(Y, bind_sub T0)] ++ E).
|
||||||
|
apply (sub_narrowing_aux T1)...
|
||||||
|
unfold transitivity_on.
|
||||||
|
auto using (IHW T1).
|
||||||
|
Qed.
|
||||||
|
|
||||||
|
Lemma sub_narrowing : forall Q E F Z P S T,
|
||||||
|
sub E P Q ->
|
||||||
|
sub (F ++ [(Z, bind_sub Q)] ++ E) S T ->
|
||||||
|
sub (F ++ [(Z, bind_sub P)] ++ E) S T.
|
||||||
|
Proof.
|
||||||
|
intros.
|
||||||
|
eapply sub_narrowing_aux; eauto.
|
||||||
|
apply sub_transitivity.
|
||||||
|
Qed.
|
||||||
|
|
||||||
|
|
||||||
|
(* ********************************************************************** *)
|
||||||
|
(** ** Type substitution preserves subtyping (10) *)
|
||||||
|
|
||||||
|
Lemma sub_through_subst_tt : forall Q E F Z S T P,
|
||||||
|
sub (F ++ [(Z, bind_sub Q)] ++ E) S T ->
|
||||||
|
sub E P Q ->
|
||||||
|
sub (map (subst_tb Z P) F ++ E) (subst_tt Z P S) (subst_tt Z P T).
|
||||||
|
Proof with
|
||||||
|
simpl_env;
|
||||||
|
eauto 4 using wf_typ_subst_tb, wf_env_subst_tb, wf_typ_weaken_head.
|
||||||
|
intros Q E F Z S T P SsubT PsubQ.
|
||||||
|
remember (F ++ [(Z, bind_sub Q)] ++ E) as G.
|
||||||
|
generalize dependent F.
|
||||||
|
induction SsubT; intros G EQ; subst; simpl subst_tt...
|
||||||
|
Case "sub_top".
|
||||||
|
apply sub_top...
|
||||||
|
Case "sub_refl_tvar".
|
||||||
|
destruct (X == Z); subst.
|
||||||
|
SCase "X = Z".
|
||||||
|
apply sub_reflexivity...
|
||||||
|
SCase "X <> Z".
|
||||||
|
apply sub_reflexivity...
|
||||||
|
inversion H0; subst.
|
||||||
|
binds_cases H3...
|
||||||
|
apply (wf_typ_var (subst_tt Z P U))...
|
||||||
|
Case "sub_trans_tvar".
|
||||||
|
destruct (X == Z); subst.
|
||||||
|
SCase "X = Z".
|
||||||
|
apply (sub_transitivity Q).
|
||||||
|
SSCase "left branch".
|
||||||
|
rewrite_env (empty ++ map (subst_tb Z P) G ++ E).
|
||||||
|
apply sub_weakening...
|
||||||
|
SSCase "right branch".
|
||||||
|
rewrite (subst_tt_fresh Z P Q).
|
||||||
|
binds_get H.
|
||||||
|
inversion H1; subst...
|
||||||
|
apply (notin_fv_wf E); eauto using fresh_mid_tail.
|
||||||
|
SCase "X <> Z".
|
||||||
|
apply (sub_trans_tvar (subst_tt Z P U))...
|
||||||
|
rewrite (map_subst_tb_id E Z P);
|
||||||
|
[ | auto | eapply fresh_mid_tail; eauto ].
|
||||||
|
binds_cases H...
|
||||||
|
Case "sub_all".
|
||||||
|
pick fresh X and apply sub_all...
|
||||||
|
rewrite subst_tt_open_tt_var...
|
||||||
|
rewrite subst_tt_open_tt_var...
|
||||||
|
rewrite_env (map (subst_tb Z P) ([(X, bind_sub T1)] ++ G) ++ E).
|
||||||
|
apply H0...
|
||||||
|
Qed.
|
||||||
|
|
||||||
|
|
||||||
|
(* ********************************************************************** *)
|
||||||
|
(** * #<a name="typing"></a># Properties of typing *)
|
||||||
|
|
||||||
|
|
||||||
|
(* ********************************************************************** *)
|
||||||
|
(** ** Weakening (5) *)
|
||||||
|
|
||||||
|
Lemma typing_weakening : forall E F G e T,
|
||||||
|
typing (G ++ E) e T ->
|
||||||
|
wf_env (G ++ F ++ E) ->
|
||||||
|
typing (G ++ F ++ E) e T.
|
||||||
|
Proof with simpl_env;
|
||||||
|
eauto using wf_typ_weakening,
|
||||||
|
wf_typ_from_wf_env_typ,
|
||||||
|
wf_typ_from_wf_env_sub,
|
||||||
|
sub_weakening.
|
||||||
|
intros E F G e T Typ.
|
||||||
|
remember (G ++ E) as H.
|
||||||
|
generalize dependent G.
|
||||||
|
induction Typ; intros G EQ Ok; subst...
|
||||||
|
Case "typing_abs".
|
||||||
|
pick fresh x and apply typing_abs.
|
||||||
|
lapply (H x); [intros K | auto].
|
||||||
|
rewrite <- concat_assoc.
|
||||||
|
apply (H0 x)...
|
||||||
|
Case "typing_tabs".
|
||||||
|
pick fresh X and apply typing_tabs.
|
||||||
|
lapply (H X); [intros K | auto].
|
||||||
|
rewrite <- concat_assoc.
|
||||||
|
apply (H0 X)...
|
||||||
|
Qed.
|
||||||
|
|
||||||
|
|
||||||
|
(* ********************************************************************** *)
|
||||||
|
(** ** Strengthening (6) *)
|
||||||
|
|
||||||
|
Lemma sub_strengthening : forall x U E F S T,
|
||||||
|
sub (F ++ [(x, bind_typ U)] ++ E) S T ->
|
||||||
|
sub (F ++ E) S T.
|
||||||
|
Proof with eauto using wf_typ_strengthening, wf_env_strengthening.
|
||||||
|
intros x U E F S T SsubT.
|
||||||
|
remember (F ++ [(x, bind_typ U)] ++ E) as E'.
|
||||||
|
generalize dependent F.
|
||||||
|
induction SsubT; intros F EQ; subst...
|
||||||
|
Case "sub_trans_tvar".
|
||||||
|
apply (sub_trans_tvar U0)...
|
||||||
|
binds_cases H...
|
||||||
|
Case "sub_all".
|
||||||
|
pick fresh X and apply sub_all...
|
||||||
|
rewrite <- concat_assoc.
|
||||||
|
apply H0...
|
||||||
|
Qed.
|
||||||
|
|
||||||
|
|
||||||
|
(************************************************************************ *)
|
||||||
|
(** ** Narrowing for typing (7) *)
|
||||||
|
|
||||||
|
Lemma typing_narrowing : forall Q E F X P e T,
|
||||||
|
sub E P Q ->
|
||||||
|
typing (F ++ [(X, bind_sub Q)] ++ E) e T ->
|
||||||
|
typing (F ++ [(X, bind_sub P)] ++ E) e T.
|
||||||
|
Proof with eauto 6 using wf_env_narrowing, wf_typ_narrowing, sub_narrowing.
|
||||||
|
intros Q E F X P e T PsubQ Typ.
|
||||||
|
remember (F ++ [(X, bind_sub Q)] ++ E) as E'.
|
||||||
|
generalize dependent F.
|
||||||
|
induction Typ; intros F EQ; subst...
|
||||||
|
Case "typing_var".
|
||||||
|
binds_cases H0...
|
||||||
|
Case "typing_abs".
|
||||||
|
pick fresh y and apply typing_abs.
|
||||||
|
rewrite <- concat_assoc.
|
||||||
|
apply H0...
|
||||||
|
Case "typing_tabs".
|
||||||
|
pick fresh Y and apply typing_tabs.
|
||||||
|
rewrite <- concat_assoc.
|
||||||
|
apply H0...
|
||||||
|
Qed.
|
||||||
|
|
||||||
|
|
||||||
|
(************************************************************************ *)
|
||||||
|
(** ** Substitution preserves typing (8) *)
|
||||||
|
|
||||||
|
Lemma typing_through_subst_ee : forall U E F x T e u,
|
||||||
|
typing (F ++ [(x, bind_typ U)] ++ E) e T ->
|
||||||
|
typing E u U ->
|
||||||
|
typing (F ++ E) (subst_ee x u e) T.
|
||||||
|
(* begin show *)
|
||||||
|
|
||||||
|
(** We provide detailed comments for the following proof, mainly to
|
||||||
|
point out several useful tactics and proof techniques.
|
||||||
|
|
||||||
|
Starting a proof with "Proof with <some tactic>" allows us to
|
||||||
|
specify a default tactic that should be used to solve goals. To
|
||||||
|
invoke this default tactic at the end of a proof step, we signal
|
||||||
|
the end of the step with three periods instead of a single one,
|
||||||
|
e.g., "apply typing_weakening...". *)
|
||||||
|
|
||||||
|
Proof with simpl_env;
|
||||||
|
eauto 4 using wf_typ_strengthening,
|
||||||
|
wf_env_strengthening,
|
||||||
|
sub_strengthening.
|
||||||
|
|
||||||
|
(** The proof proceeds by induction on the given typing derivation
|
||||||
|
for e. We use the remember tactic, along with generalize
|
||||||
|
dependent, to ensure that the goal is properly strengthened
|
||||||
|
before we use induction. *)
|
||||||
|
|
||||||
|
intros U E F x T e u TypT TypU.
|
||||||
|
remember (F ++ [(x, bind_typ U)] ++ E) as E'.
|
||||||
|
generalize dependent F.
|
||||||
|
induction TypT; intros F EQ; subst; simpl subst_ee...
|
||||||
|
|
||||||
|
(** The typing_var case involves a case analysis on whether the
|
||||||
|
variable is the same as the one being substituted for. *)
|
||||||
|
|
||||||
|
Case "typing_var".
|
||||||
|
destruct (x0 == x); subst.
|
||||||
|
|
||||||
|
(** In the case where x0=x, we first observe that hypothesis H0
|
||||||
|
implies that T=U, since x can only be bound once in the
|
||||||
|
environment. The conclusion then follows from hypothesis TypU
|
||||||
|
and weakening. We can use the binds_get tactic, described in
|
||||||
|
the Environment library, with H0 to obtain the fact that
|
||||||
|
T=U. *)
|
||||||
|
|
||||||
|
SCase "x0 = x".
|
||||||
|
binds_get H0.
|
||||||
|
inversion H2; subst.
|
||||||
|
|
||||||
|
(** In order to apply typing_weakening, we need to rewrite the
|
||||||
|
environment so that it has the right shape. (We could
|
||||||
|
also prove a corollary of typing_weakening.) The
|
||||||
|
rewrite_env tactic, described in the Environment library,
|
||||||
|
is one way to perform this rewriting. *)
|
||||||
|
|
||||||
|
rewrite_env (empty ++ F ++ E).
|
||||||
|
apply typing_weakening...
|
||||||
|
|
||||||
|
(** In the case where x0<>x, the result follows by an exhaustive
|
||||||
|
case analysis on exactly where x0 is bound in the environment.
|
||||||
|
We perform this case analysis by using the binds_cases tactic,
|
||||||
|
described in the Environment library. *)
|
||||||
|
|
||||||
|
SCase "x0 <> x".
|
||||||
|
binds_cases H0.
|
||||||
|
eauto using wf_env_strengthening.
|
||||||
|
eauto using wf_env_strengthening.
|
||||||
|
|
||||||
|
(** Informally, the typing_abs case is a straightforward application
|
||||||
|
of the induction hypothesis, which is called H0 here. *)
|
||||||
|
|
||||||
|
Case "typing_abs".
|
||||||
|
|
||||||
|
(** We use the "pick fresh and apply" tactic to apply the rule
|
||||||
|
typing_abs without having to calculate the appropriate finite
|
||||||
|
set of atoms. *)
|
||||||
|
|
||||||
|
pick fresh y and apply typing_abs.
|
||||||
|
|
||||||
|
(** We cannot apply H0 directly here. The first problem is that
|
||||||
|
the induction hypothesis has (subst_ee open_ee), whereas in
|
||||||
|
the goal we have (open_ee subst_ee). The lemma
|
||||||
|
subst_ee_open_ee_var lets us swap the order of these two
|
||||||
|
operations. *)
|
||||||
|
|
||||||
|
rewrite subst_ee_open_ee_var...
|
||||||
|
|
||||||
|
(** The second problem is how the concatenations are associated in
|
||||||
|
the environments. In the goal, we currently have
|
||||||
|
|
||||||
|
<< ([(y, bind_typ V)] ++ F ++ E),
|
||||||
|
>>
|
||||||
|
where concatenation associates to the right. In order to
|
||||||
|
apply the induction hypothesis, we need
|
||||||
|
|
||||||
|
<< (([(y, bind_typ V)] ++ F) ++ E).
|
||||||
|
>>
|
||||||
|
We can use the rewrite_env tactic to perform this rewriting,
|
||||||
|
or we can rewrite directly with an appropriate lemma from the
|
||||||
|
Environment library. *)
|
||||||
|
|
||||||
|
rewrite <- concat_assoc.
|
||||||
|
|
||||||
|
(** Now we can apply the induction hypothesis. *)
|
||||||
|
|
||||||
|
apply H0...
|
||||||
|
|
||||||
|
(** The remaining cases in this proof are straightforward, given
|
||||||
|
everything that we have pointed out above. *)
|
||||||
|
|
||||||
|
Case "typing_tabs".
|
||||||
|
pick fresh Y and apply typing_tabs.
|
||||||
|
rewrite subst_ee_open_te_var...
|
||||||
|
rewrite <- concat_assoc.
|
||||||
|
apply H0...
|
||||||
|
Qed.
|
||||||
|
(* end show *)
|
||||||
|
|
||||||
|
|
||||||
|
(************************************************************************ *)
|
||||||
|
(** ** Type substitution preserves typing (11) *)
|
||||||
|
|
||||||
|
Lemma typing_through_subst_te : forall Q E F Z e T P,
|
||||||
|
typing (F ++ [(Z, bind_sub Q)] ++ E) e T ->
|
||||||
|
sub E P Q ->
|
||||||
|
typing (map (subst_tb Z P) F ++ E) (subst_te Z P e) (subst_tt Z P T).
|
||||||
|
Proof with simpl_env;
|
||||||
|
eauto 6 using wf_env_subst_tb,
|
||||||
|
wf_typ_subst_tb,
|
||||||
|
sub_through_subst_tt.
|
||||||
|
intros Q E F Z e T P Typ PsubQ.
|
||||||
|
remember (F ++ [(Z, bind_sub Q)] ++ E) as G.
|
||||||
|
generalize dependent F.
|
||||||
|
induction Typ; intros F EQ; subst;
|
||||||
|
simpl subst_te in *; simpl subst_tt in *...
|
||||||
|
Case "typing_var".
|
||||||
|
apply typing_var...
|
||||||
|
rewrite (map_subst_tb_id E Z P);
|
||||||
|
[ | auto | eapply fresh_mid_tail; eauto ].
|
||||||
|
binds_cases H0...
|
||||||
|
Case "typing_abs".
|
||||||
|
pick fresh y and apply typing_abs.
|
||||||
|
rewrite subst_te_open_ee_var...
|
||||||
|
rewrite_env (map (subst_tb Z P) ([(y, bind_typ V)] ++ F) ++ E).
|
||||||
|
apply H0...
|
||||||
|
Case "typing_tabs".
|
||||||
|
pick fresh Y and apply typing_tabs.
|
||||||
|
rewrite subst_te_open_te_var...
|
||||||
|
rewrite subst_tt_open_tt_var...
|
||||||
|
rewrite_env (map (subst_tb Z P) ([(Y, bind_sub V)] ++ F) ++ E).
|
||||||
|
apply H0...
|
||||||
|
Case "typing_tapp".
|
||||||
|
rewrite subst_tt_open_tt...
|
||||||
|
Qed.
|
||||||
|
|
||||||
|
|
||||||
|
(* ********************************************************************** *)
|
||||||
|
(** * #<a name="preservation"></a># Preservation *)
|
||||||
|
|
||||||
|
|
||||||
|
(* ********************************************************************** *)
|
||||||
|
(** ** Inversion of typing (13) *)
|
||||||
|
|
||||||
|
Lemma typing_inv_abs : forall E S1 e1 T,
|
||||||
|
typing E (exp_abs S1 e1) T ->
|
||||||
|
forall U1 U2, sub E T (typ_arrow U1 U2) ->
|
||||||
|
sub E U1 S1
|
||||||
|
/\ exists S2, exists L, forall x, x `notin` L ->
|
||||||
|
typing ([(x, bind_typ S1)] ++ E) (open_ee e1 x) S2 /\ sub E S2 U2.
|
||||||
|
Proof with auto.
|
||||||
|
intros E S1 e1 T Typ.
|
||||||
|
remember (exp_abs S1 e1) as e.
|
||||||
|
generalize dependent e1.
|
||||||
|
generalize dependent S1.
|
||||||
|
induction Typ; intros S1 b1 EQ U1 U2 Sub; inversion EQ; subst.
|
||||||
|
Case "typing_abs".
|
||||||
|
inversion Sub; subst.
|
||||||
|
split...
|
||||||
|
exists T1. exists L...
|
||||||
|
Case "typing_sub".
|
||||||
|
auto using (sub_transitivity T).
|
||||||
|
Qed.
|
||||||
|
|
||||||
|
Lemma typing_inv_tabs : forall E S1 e1 T,
|
||||||
|
typing E (exp_tabs S1 e1) T ->
|
||||||
|
forall U1 U2, sub E T (typ_all U1 U2) ->
|
||||||
|
sub E U1 S1
|
||||||
|
/\ exists S2, exists L, forall X, X `notin` L ->
|
||||||
|
typing ([(X, bind_sub U1)] ++ E) (open_te e1 X) (open_tt S2 X)
|
||||||
|
/\ sub ([(X, bind_sub U1)] ++ E) (open_tt S2 X) (open_tt U2 X).
|
||||||
|
Proof with simpl_env; auto.
|
||||||
|
intros E S1 e1 T Typ.
|
||||||
|
remember (exp_tabs S1 e1) as e.
|
||||||
|
generalize dependent e1.
|
||||||
|
generalize dependent S1.
|
||||||
|
induction Typ; intros S1 e0 EQ U1 U2 Sub; inversion EQ; subst.
|
||||||
|
Case "typing_tabs".
|
||||||
|
inversion Sub; subst.
|
||||||
|
split...
|
||||||
|
exists T1.
|
||||||
|
exists (L0 `union` L).
|
||||||
|
intros Y Fr.
|
||||||
|
split...
|
||||||
|
rewrite_env (empty ++ [(Y, bind_sub U1)] ++ E).
|
||||||
|
apply (typing_narrowing S1)...
|
||||||
|
Case "typing_sub".
|
||||||
|
auto using (sub_transitivity T).
|
||||||
|
Qed.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
(* ********************************************************************** *)
|
||||||
|
(** ** Preservation (20) *)
|
||||||
|
|
||||||
|
Lemma preservation : forall E e e' T,
|
||||||
|
typing E e T ->
|
||||||
|
red e e' ->
|
||||||
|
typing E e' T.
|
||||||
|
Proof with simpl_env; eauto.
|
||||||
|
intros E e e' T Typ. generalize dependent e'.
|
||||||
|
induction Typ; intros e' Red; try solve [ inversion Red; subst; eauto ].
|
||||||
|
Case "typing_app".
|
||||||
|
inversion Red; subst...
|
||||||
|
SCase "red_abs".
|
||||||
|
destruct (typing_inv_abs _ _ _ _ Typ1 T1 T2) as [P1 [S2 [L P2]]].
|
||||||
|
apply sub_reflexivity...
|
||||||
|
pick fresh x.
|
||||||
|
destruct (P2 x) as [? ?]...
|
||||||
|
rewrite (subst_ee_intro x)...
|
||||||
|
rewrite_env (empty ++ E).
|
||||||
|
apply (typing_through_subst_ee T).
|
||||||
|
apply (typing_sub S2)...
|
||||||
|
rewrite_env (empty ++ [(x, bind_typ T)] ++ E).
|
||||||
|
apply sub_weakening...
|
||||||
|
eauto.
|
||||||
|
Case "typing_tapp".
|
||||||
|
inversion Red; subst...
|
||||||
|
SCase "red_tabs".
|
||||||
|
destruct (typing_inv_tabs _ _ _ _ Typ T1 T2) as [P1 [S2 [L P2]]].
|
||||||
|
apply sub_reflexivity...
|
||||||
|
pick fresh X.
|
||||||
|
destruct (P2 X) as [? ?]...
|
||||||
|
rewrite (subst_te_intro X)...
|
||||||
|
rewrite (subst_tt_intro X)...
|
||||||
|
rewrite_env (map (subst_tb X T) empty ++ E).
|
||||||
|
apply (typing_through_subst_te T1)...
|
||||||
|
Qed.
|
||||||
|
|
||||||
|
|
||||||
|
(* ********************************************************************** *)
|
||||||
|
(** * #<a name="progress"></a># Progress *)
|
||||||
|
|
||||||
|
|
||||||
|
(* ********************************************************************** *)
|
||||||
|
(** ** Canonical forms (14) *)
|
||||||
|
|
||||||
|
Lemma canonical_form_abs : forall e U1 U2,
|
||||||
|
value e ->
|
||||||
|
typing empty e (typ_arrow U1 U2) ->
|
||||||
|
exists V, exists e1, e = exp_abs V e1.
|
||||||
|
Proof.
|
||||||
|
intros e U1 U2 Val Typ.
|
||||||
|
remember empty as E.
|
||||||
|
remember (typ_arrow U1 U2) as T.
|
||||||
|
revert U1 U2 HeqT HeqE.
|
||||||
|
induction Typ; intros U1 U2 EQT EQE; subst;
|
||||||
|
try solve [ inversion Val | inversion EQT | eauto ].
|
||||||
|
Case "typing_sub".
|
||||||
|
inversion H; subst; eauto.
|
||||||
|
inversion H0.
|
||||||
|
Qed.
|
||||||
|
|
||||||
|
Lemma canonical_form_tabs : forall e U1 U2,
|
||||||
|
value e ->
|
||||||
|
typing empty e (typ_all U1 U2) ->
|
||||||
|
exists V, exists e1, e = exp_tabs V e1.
|
||||||
|
Proof.
|
||||||
|
intros e U1 U2 Val Typ.
|
||||||
|
remember empty as E.
|
||||||
|
remember (typ_all U1 U2) as T.
|
||||||
|
revert U1 U2 HeqT HeqT.
|
||||||
|
induction Typ; intros U1 U2 EQT EQE; subst;
|
||||||
|
try solve [ inversion Val | inversion EQT | eauto ].
|
||||||
|
Case "typing_sub".
|
||||||
|
inversion H; subst; eauto.
|
||||||
|
inversion H0.
|
||||||
|
Qed.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
(* ********************************************************************** *)
|
||||||
|
(** ** Progress (16) *)
|
||||||
|
|
||||||
|
Lemma progress : forall e T,
|
||||||
|
typing empty e T ->
|
||||||
|
value e \/ exists e', red e e'.
|
||||||
|
Proof with eauto.
|
||||||
|
intros e T Typ.
|
||||||
|
remember empty as E. generalize dependent HeqE.
|
||||||
|
assert (Typ' : typing E e T)...
|
||||||
|
induction Typ; intros EQ; subst...
|
||||||
|
Case "typing_var".
|
||||||
|
inversion H0.
|
||||||
|
Case "typing_app".
|
||||||
|
right.
|
||||||
|
destruct IHTyp1 as [Val1 | [e1' Rede1']]...
|
||||||
|
SCase "Val1".
|
||||||
|
destruct IHTyp2 as [Val2 | [e2' Rede2']]...
|
||||||
|
SSCase "Val2".
|
||||||
|
destruct (canonical_form_abs _ _ _ Val1 Typ1) as [S [e3 EQ]].
|
||||||
|
subst.
|
||||||
|
exists (open_ee e3 e2)...
|
||||||
|
Case "typing_tapp".
|
||||||
|
right.
|
||||||
|
destruct IHTyp as [Val1 | [e1' Rede1']]...
|
||||||
|
SCase "Val1".
|
||||||
|
destruct (canonical_form_tabs _ _ _ Val1 Typ) as [S [e3 EQ]].
|
||||||
|
subst.
|
||||||
|
exists (open_te e3 T)...
|
||||||
|
SCase "e1' Rede1'".
|
||||||
|
exists (exp_tapp e1' T)...
|
||||||
|
Qed.
|
283
coq-Fsub/ListFacts.v
Normal file
283
coq-Fsub/ListFacts.v
Normal file
|
@ -0,0 +1,283 @@
|
||||||
|
(** Assorted facts about lists.
|
||||||
|
|
||||||
|
Author: Brian Aydemir.
|
||||||
|
|
||||||
|
Implicit arguments are declared by default in this library. *)
|
||||||
|
|
||||||
|
Set Implicit Arguments.
|
||||||
|
|
||||||
|
Require Import Eqdep_dec.
|
||||||
|
Require Import List.
|
||||||
|
Require Import SetoidList.
|
||||||
|
Require Import Sorting.
|
||||||
|
Require Import Relations.
|
||||||
|
|
||||||
|
|
||||||
|
(* ********************************************************************** *)
|
||||||
|
(** * List membership *)
|
||||||
|
|
||||||
|
Lemma not_in_cons :
|
||||||
|
forall (A : Type) (ys : list A) x y,
|
||||||
|
x <> y -> ~ In x ys -> ~ In x (y :: ys).
|
||||||
|
Proof.
|
||||||
|
induction ys; simpl; intuition.
|
||||||
|
Qed.
|
||||||
|
|
||||||
|
Lemma not_In_app :
|
||||||
|
forall (A : Type) (xs ys : list A) x,
|
||||||
|
~ In x xs -> ~ In x ys -> ~ In x (xs ++ ys).
|
||||||
|
Proof.
|
||||||
|
intros A xs ys x H J K.
|
||||||
|
destruct (in_app_or _ _ _ K); auto.
|
||||||
|
Qed.
|
||||||
|
|
||||||
|
Lemma elim_not_In_cons :
|
||||||
|
forall (A : Type) (y : A) (ys : list A) (x : A),
|
||||||
|
~ In x (y :: ys) -> x <> y /\ ~ In x ys.
|
||||||
|
Proof.
|
||||||
|
intros. simpl in *. auto.
|
||||||
|
Qed.
|
||||||
|
|
||||||
|
Lemma elim_not_In_app :
|
||||||
|
forall (A : Type) (xs ys : list A) (x : A),
|
||||||
|
~ In x (xs ++ ys) -> ~ In x xs /\ ~ In x ys.
|
||||||
|
Proof.
|
||||||
|
split; auto using in_or_app.
|
||||||
|
Qed.
|
||||||
|
|
||||||
|
|
||||||
|
(* ********************************************************************** *)
|
||||||
|
(** * List inclusion *)
|
||||||
|
|
||||||
|
Lemma incl_nil :
|
||||||
|
forall (A : Type) (xs : list A), incl nil xs.
|
||||||
|
Proof.
|
||||||
|
unfold incl.
|
||||||
|
intros A xs a H; inversion H.
|
||||||
|
Qed.
|
||||||
|
|
||||||
|
Lemma incl_trans :
|
||||||
|
forall (A : Type) (xs ys zs : list A),
|
||||||
|
incl xs ys -> incl ys zs -> incl xs zs.
|
||||||
|
Proof.
|
||||||
|
unfold incl; firstorder.
|
||||||
|
Qed.
|
||||||
|
|
||||||
|
Lemma In_incl :
|
||||||
|
forall (A : Type) (x : A) (ys zs : list A),
|
||||||
|
In x ys -> incl ys zs -> In x zs.
|
||||||
|
Proof.
|
||||||
|
unfold incl; auto.
|
||||||
|
Qed.
|
||||||
|
|
||||||
|
Lemma elim_incl_cons :
|
||||||
|
forall (A : Type) (x : A) (xs zs : list A),
|
||||||
|
incl (x :: xs) zs -> In x zs /\ incl xs zs.
|
||||||
|
Proof.
|
||||||
|
unfold incl. auto with datatypes.
|
||||||
|
Qed.
|
||||||
|
|
||||||
|
Lemma elim_incl_app :
|
||||||
|
forall (A : Type) (xs ys zs : list A),
|
||||||
|
incl (xs ++ ys) zs -> incl xs zs /\ incl ys zs.
|
||||||
|
Proof.
|
||||||
|
unfold incl. auto with datatypes.
|
||||||
|
Qed.
|
||||||
|
|
||||||
|
|
||||||
|
(* ********************************************************************** *)
|
||||||
|
(** * Setoid facts *)
|
||||||
|
|
||||||
|
Lemma InA_iff_In :
|
||||||
|
forall (A : Set) x xs, InA (@eq A) x xs <-> In x xs.
|
||||||
|
Proof.
|
||||||
|
split. 2:auto using In_InA.
|
||||||
|
induction xs as [ | y ys IH ].
|
||||||
|
intros H. inversion H.
|
||||||
|
intros H. inversion H; subst; auto with datatypes.
|
||||||
|
Qed.
|
||||||
|
|
||||||
|
|
||||||
|
(* ********************************************************************* *)
|
||||||
|
(** * Equality proofs for lists *)
|
||||||
|
|
||||||
|
Section EqRectList.
|
||||||
|
|
||||||
|
Variable A : Type.
|
||||||
|
Variable eq_A_dec : forall (x y : A), {x = y} + {x <> y}.
|
||||||
|
|
||||||
|
Lemma eq_rect_eq_list :
|
||||||
|
forall (p : list A) (Q : list A -> Type) (x : Q p) (h : p = p),
|
||||||
|
eq_rect p Q x p h = x.
|
||||||
|
Proof with auto.
|
||||||
|
intros.
|
||||||
|
apply K_dec with (p := h)...
|
||||||
|
decide equality. destruct (eq_A_dec a a0)...
|
||||||
|
Qed.
|
||||||
|
|
||||||
|
End EqRectList.
|
||||||
|
|
||||||
|
|
||||||
|
(* ********************************************************************** *)
|
||||||
|
(** * Decidable sorting and uniqueness of proofs *)
|
||||||
|
|
||||||
|
Section DecidableSorting.
|
||||||
|
|
||||||
|
Variable A : Set.
|
||||||
|
Variable leA : relation A.
|
||||||
|
Hypothesis leA_dec : forall x y, {leA x y} + {~ leA x y}.
|
||||||
|
|
||||||
|
Theorem lelistA_dec :
|
||||||
|
forall a xs, {lelistA leA a xs} + {~ lelistA leA a xs}.
|
||||||
|
Proof.
|
||||||
|
induction xs as [ | x xs IH ]; auto with datatypes.
|
||||||
|
destruct (leA_dec a x); auto with datatypes.
|
||||||
|
right. intros J. inversion J. auto.
|
||||||
|
Qed.
|
||||||
|
|
||||||
|
Theorem sort_dec :
|
||||||
|
forall xs, {sort leA xs} + {~ sort leA xs}.
|
||||||
|
Proof.
|
||||||
|
induction xs as [ | x xs IH ]; auto with datatypes.
|
||||||
|
destruct IH; destruct (lelistA_dec x xs); auto with datatypes.
|
||||||
|
right. intros K. inversion K. auto.
|
||||||
|
right. intros K. inversion K. auto.
|
||||||
|
right. intros K. inversion K. auto.
|
||||||
|
Qed.
|
||||||
|
|
||||||
|
Section UniqueSortingProofs.
|
||||||
|
|
||||||
|
Hypothesis eq_A_dec : forall (x y : A), {x = y} + {x <> y}.
|
||||||
|
Hypothesis leA_unique : forall (x y : A) (p q : leA x y), p = q.
|
||||||
|
|
||||||
|
Scheme lelistA_ind' := Induction for lelistA Sort Prop.
|
||||||
|
Scheme sort_ind' := Induction for sort Sort Prop.
|
||||||
|
|
||||||
|
Theorem lelistA_unique :
|
||||||
|
forall (x : A) (xs : list A) (p q : lelistA leA x xs), p = q.
|
||||||
|
Proof with auto.
|
||||||
|
induction p using lelistA_ind'; intros q.
|
||||||
|
(* case: nil_leA *)
|
||||||
|
replace (nil_leA leA x) with (eq_rect _ (fun xs => lelistA leA x xs)
|
||||||
|
(nil_leA leA x) _ (refl_equal (@nil A)))...
|
||||||
|
generalize (refl_equal (@nil A)).
|
||||||
|
pattern (@nil A) at 1 3 4 6, q. case q; [ | intros; discriminate ].
|
||||||
|
intros. rewrite eq_rect_eq_list...
|
||||||
|
(* case: cons_sort *)
|
||||||
|
replace (cons_leA leA x b l l0) with (eq_rect _ (fun xs => lelistA leA x xs)
|
||||||
|
(cons_leA leA x b l l0) _ (refl_equal (b :: l)))...
|
||||||
|
generalize (refl_equal (b :: l)).
|
||||||
|
pattern (b :: l) at 1 3 4 6, q. case q; [ intros; discriminate | ].
|
||||||
|
intros. inversion e; subst.
|
||||||
|
rewrite eq_rect_eq_list...
|
||||||
|
rewrite (leA_unique l0 l2)...
|
||||||
|
Qed.
|
||||||
|
|
||||||
|
Theorem sort_unique :
|
||||||
|
forall (xs : list A) (p q : sort leA xs), p = q.
|
||||||
|
Proof with auto.
|
||||||
|
induction p using sort_ind'; intros q.
|
||||||
|
(* case: nil_sort *)
|
||||||
|
replace (nil_sort leA) with (eq_rect _ (fun xs => sort leA xs)
|
||||||
|
(nil_sort leA) _ (refl_equal (@nil A)))...
|
||||||
|
generalize (refl_equal (@nil A)).
|
||||||
|
pattern (@nil A) at 1 3 4 6, q. case q; [ | intros; discriminate ].
|
||||||
|
intros. rewrite eq_rect_eq_list...
|
||||||
|
(* case: cons_sort *)
|
||||||
|
replace (cons_sort p l0) with (eq_rect _ (fun xs => sort leA xs)
|
||||||
|
(cons_sort p l0) _ (refl_equal (a :: l)))...
|
||||||
|
generalize (refl_equal (a :: l)).
|
||||||
|
pattern (a :: l) at 1 3 4 6, q. case q; [ intros; discriminate | ].
|
||||||
|
intros. inversion e; subst.
|
||||||
|
rewrite eq_rect_eq_list...
|
||||||
|
rewrite (lelistA_unique l0 l2).
|
||||||
|
rewrite (IHp s)...
|
||||||
|
Qed.
|
||||||
|
|
||||||
|
End UniqueSortingProofs.
|
||||||
|
End DecidableSorting.
|
||||||
|
|
||||||
|
|
||||||
|
(* ********************************************************************** *)
|
||||||
|
(** * Equality on sorted lists *)
|
||||||
|
|
||||||
|
Section Equality_ext.
|
||||||
|
|
||||||
|
Variable A : Set.
|
||||||
|
Variable ltA : relation A.
|
||||||
|
Hypothesis ltA_trans : forall x y z, ltA x y -> ltA y z -> ltA x z.
|
||||||
|
Hypothesis ltA_not_eqA : forall x y, ltA x y -> x <> y.
|
||||||
|
Hypothesis ltA_eqA : forall x y z, ltA x y -> y = z -> ltA x z.
|
||||||
|
Hypothesis eqA_ltA : forall x y z, x = y -> ltA y z -> ltA x z.
|
||||||
|
|
||||||
|
Hint Resolve ltA_trans.
|
||||||
|
Hint Immediate ltA_eqA eqA_ltA.
|
||||||
|
|
||||||
|
Notation Inf := (lelistA ltA).
|
||||||
|
Notation Sort := (sort ltA).
|
||||||
|
|
||||||
|
Lemma not_InA_if_Sort_Inf :
|
||||||
|
forall xs a, Sort xs -> Inf a xs -> ~ InA (@eq A) a xs.
|
||||||
|
Proof.
|
||||||
|
induction xs as [ | x xs IH ]; intros a Hsort Hinf H.
|
||||||
|
inversion H.
|
||||||
|
inversion H; subst.
|
||||||
|
inversion Hinf; subst.
|
||||||
|
assert (x <> x) by auto; intuition.
|
||||||
|
inversion Hsort; inversion Hinf; subst.
|
||||||
|
assert (Inf a xs) by eauto using InfA_ltA.
|
||||||
|
assert (~ InA (@eq A) a xs) by auto.
|
||||||
|
intuition.
|
||||||
|
Qed.
|
||||||
|
|
||||||
|
Lemma Sort_eq_head :
|
||||||
|
forall x xs y ys,
|
||||||
|
Sort (x :: xs) ->
|
||||||
|
Sort (y :: ys) ->
|
||||||
|
(forall a, InA (@eq A) a (x :: xs) <-> InA (@eq A) a (y :: ys)) ->
|
||||||
|
x = y.
|
||||||
|
Proof.
|
||||||
|
intros x xs y ys SortXS SortYS H.
|
||||||
|
inversion SortXS; inversion SortYS; subst.
|
||||||
|
assert (Q3 : InA (@eq A) x (y :: ys)) by firstorder.
|
||||||
|
assert (Q4 : InA (@eq A) y (x :: xs)) by firstorder.
|
||||||
|
inversion Q3; subst; auto.
|
||||||
|
inversion Q4; subst; auto.
|
||||||
|
assert (ltA y x) by (refine (SortA_InfA_InA _ _ _ _ _ H6 H7 H1); auto).
|
||||||
|
assert (ltA x y) by (refine (SortA_InfA_InA _ _ _ _ _ H2 H3 H4); auto).
|
||||||
|
assert (y <> y) by eauto.
|
||||||
|
intuition.
|
||||||
|
Qed.
|
||||||
|
|
||||||
|
Lemma Sort_InA_eq_ext :
|
||||||
|
forall xs ys,
|
||||||
|
Sort xs ->
|
||||||
|
Sort ys ->
|
||||||
|
(forall a, InA (@eq A) a xs <-> InA (@eq A) a ys) ->
|
||||||
|
xs = ys.
|
||||||
|
Proof.
|
||||||
|
induction xs as [ | x xs IHxs ]; induction ys as [ | y ys IHys ];
|
||||||
|
intros SortXS SortYS H; auto.
|
||||||
|
(* xs -> nil, ys -> y :: ys *)
|
||||||
|
assert (Q : InA (@eq A) y nil) by firstorder.
|
||||||
|
inversion Q.
|
||||||
|
(* xs -> x :: xs, ys -> nil *)
|
||||||
|
assert (Q : InA (@eq A) x nil) by firstorder.
|
||||||
|
inversion Q.
|
||||||
|
(* xs -> x :: xs, ys -> y :: ys *)
|
||||||
|
inversion SortXS; inversion SortYS; subst.
|
||||||
|
assert (x = y) by eauto using Sort_eq_head.
|
||||||
|
cut (forall a, InA (@eq A) a xs <-> InA (@eq A) a ys).
|
||||||
|
intros. assert (xs = ys) by auto. subst. auto.
|
||||||
|
intros a; split; intros L.
|
||||||
|
assert (Q2 : InA (@eq A) a (y :: ys)) by firstorder.
|
||||||
|
inversion Q2; subst; auto.
|
||||||
|
assert (Q5 : ~ InA (@eq A) y xs) by auto using not_InA_if_Sort_Inf.
|
||||||
|
intuition.
|
||||||
|
assert (Q2 : InA (@eq A) a (x :: xs)) by firstorder.
|
||||||
|
inversion Q2; subst; auto.
|
||||||
|
assert (Q5 : ~ InA (@eq A) y ys) by auto using not_InA_if_Sort_Inf.
|
||||||
|
intuition.
|
||||||
|
Qed.
|
||||||
|
|
||||||
|
End Equality_ext.
|
95
coq-Fsub/Metatheory.v
Normal file
95
coq-Fsub/Metatheory.v
Normal file
|
@ -0,0 +1,95 @@
|
||||||
|
(** Library for programming languages metatheory.
|
||||||
|
|
||||||
|
Authors: Brian Aydemir and Arthur Charguéraud, with help from
|
||||||
|
Aaron Bohannon, Benjamin Pierce, Jeffrey Vaughan, Dimitrios
|
||||||
|
Vytiniotis, Stephanie Weirich, and Steve Zdancewic. *)
|
||||||
|
|
||||||
|
Require Export AdditionalTactics.
|
||||||
|
Require Export Atom.
|
||||||
|
Require Export Environment.
|
||||||
|
|
||||||
|
|
||||||
|
(* ********************************************************************** *)
|
||||||
|
(** * Notations *)
|
||||||
|
|
||||||
|
(** Decidable equality on atoms and natural numbers may be written
|
||||||
|
using natural notation. *)
|
||||||
|
|
||||||
|
Notation "x == y" :=
|
||||||
|
(eq_atom_dec x y) (at level 67) : metatheory_scope.
|
||||||
|
Notation "i === j" :=
|
||||||
|
(Peano_dec.eq_nat_dec i j) (at level 67) : metatheory_scope.
|
||||||
|
|
||||||
|
(** Common set operations may be written using infix notation. *)
|
||||||
|
|
||||||
|
Notation "E `union` F" :=
|
||||||
|
(AtomSet.F.union E F)
|
||||||
|
(at level 69, right associativity, format "E `union` '/' F")
|
||||||
|
: set_scope.
|
||||||
|
Notation "x `in` E" :=
|
||||||
|
(AtomSet.F.In x E) (at level 69) : set_scope.
|
||||||
|
Notation "x `notin` E" :=
|
||||||
|
(~ AtomSet.F.In x E) (at level 69) : set_scope.
|
||||||
|
|
||||||
|
(** The empty set may be written similarly to informal practice. *)
|
||||||
|
|
||||||
|
Notation "{}" :=
|
||||||
|
(AtomSet.F.empty) : metatheory_scope.
|
||||||
|
|
||||||
|
(** It is useful to have an abbreviation for constructing singleton
|
||||||
|
sets. *)
|
||||||
|
|
||||||
|
Notation singleton := (AtomSet.F.singleton).
|
||||||
|
|
||||||
|
(** Open the notation scopes declared above. *)
|
||||||
|
|
||||||
|
Open Scope metatheory_scope.
|
||||||
|
Open Scope set_scope.
|
||||||
|
|
||||||
|
|
||||||
|
(* ********************************************************************** *)
|
||||||
|
(** * Tactic for working with cofinite quantification *)
|
||||||
|
|
||||||
|
(** Consider a rule [H] (equivalently, hypothesis, constructor, lemma,
|
||||||
|
etc.) of the form [(forall L ..., ... -> (forall y, y `notin` L ->
|
||||||
|
P) -> ... -> Q)], where [Q]'s outermost constructor is not a
|
||||||
|
[forall]. There may be multiple hypotheses of with the indicated
|
||||||
|
form in [H].
|
||||||
|
|
||||||
|
The tactic [(pick fresh x and apply H)] applies [H] to the current
|
||||||
|
goal, instantiating [H]'s first argument (i.e., [L]) with the
|
||||||
|
finite set of atoms [L']. In each new subgoal arising from a
|
||||||
|
hypothesis of the form [(forall y, y `notin` L -> P)], the atom
|
||||||
|
[y] is introduced as [x], and [(y `notin` L)] is introduced using
|
||||||
|
a generated name.
|
||||||
|
|
||||||
|
If we view [H] as a rule that uses cofinite quantification, the
|
||||||
|
tactic can be read as picking a sufficiently fresh atom to open a
|
||||||
|
term with. *)
|
||||||
|
|
||||||
|
Tactic Notation
|
||||||
|
"pick" "fresh" ident(atom_name)
|
||||||
|
"excluding" constr(L)
|
||||||
|
"and" "apply" constr(H) :=
|
||||||
|
let L := beautify_fset L in
|
||||||
|
first [apply (@H L) | eapply (@H L)];
|
||||||
|
match goal with
|
||||||
|
| |- forall _, _ `notin` _ -> _ =>
|
||||||
|
let Fr := fresh "Fr" in intros atom_name Fr
|
||||||
|
| |- forall _, _ `notin` _ -> _ =>
|
||||||
|
fail 1 "because" atom_name "is already defined"
|
||||||
|
| _ =>
|
||||||
|
idtac
|
||||||
|
end.
|
||||||
|
|
||||||
|
|
||||||
|
(* ********************************************************************** *)
|
||||||
|
(** * Automation *)
|
||||||
|
|
||||||
|
(** These hints should discharge many of the freshness and inequality
|
||||||
|
goals that arise in programming language metatheory proofs, in
|
||||||
|
particular those arising from cofinite quantification. *)
|
||||||
|
|
||||||
|
Hint Resolve notin_empty notin_singleton notin_union.
|
||||||
|
Hint Extern 4 (_ `notin` _) => simpl_env; notin_solve.
|
||||||
|
Hint Extern 4 (_ <> _ :> atom) => simpl_env; notin_solve.
|
13
coq-Fsub/_CoqProject
Normal file
13
coq-Fsub/_CoqProject
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
-R . Fsub
|
||||||
|
AdditionalTactics.v
|
||||||
|
FSetDecide.v
|
||||||
|
FSetNotin.v
|
||||||
|
ListFacts.v
|
||||||
|
FiniteSets.v
|
||||||
|
Atom.v
|
||||||
|
Metatheory.v
|
||||||
|
Fsub_Definitions.v
|
||||||
|
Fsub_Infrastructure.v
|
||||||
|
Fsub_Lemmas.v
|
||||||
|
Fsub_Soundness.v
|
||||||
|
|
Loading…
Reference in a new issue