Built with Alectryon, running Coq+SerAPI v8.16.0+0.16.3. Bubbles () indicate interactive fragments: hover for details, tap to reveal contents. Use Ctrl+↑Ctrl+↓ to navigate, Ctrl+🖱️ to focus. On Mac, use ⌘ instead of Ctrl.
From Tealeaves Require Import
Common.Names
Common.AtomSet
Classes.Categorical.Monad (Return, ret)
Classes.Categorical.Comonad (Extract, extract)
Classes.Categorical.ShapelyFunctor
Classes.Kleisli.TraversableFunctor
Functors.Writer.From Coq Require Import
Logic.Decidable
Sorting.Permutation.Import Product.Notations.Import List.ListNotations.Import AtomSet.Notations.Import ContainerFunctor.Notations.Create HintDb tea_alist.(** * The <<alist>> functor *)(******************************************************************************)(** An association list is a list of pairs of type <<atom * A>>. Afunctor instance is provided by mapping over <<A>>, leaving atomsalone. Technically the functor is the composition of [list] and<<prod atom>>. *)(******************************************************************************)ModuleNotations.Notation"'one'" := (ret (T := list)).Notation"x ~ a" := (ret (T := list) (x, a)) (at level50).EndNotations.Import Notations.Definitionalist := list ∘ (atom ×).(** ** Functor instance for <<alist>> *)(******************************************************************************)#[export] InstanceFunctor_alist : Functor alist :=
Functor_compose list (prod atom).(** ** DT functor instance for <<alist>> *)(******************************************************************************)SectionDecoratedTraversableFunctor_alist.(* (** ** Traversable instance *) (******************************************************************************) #[global] Instance Dist_alist : Dist alist := Dist_compose. #[global] Instance Traversable_alist : TraversableFunctor alist := Traversable_compose. (** ** Decorated instance *) (******************************************************************************) #[global] Instance Decorate_alist : Decorate W (alist) := Decorate_zero. #[global] Instance DecoratedFunctor_alist : Algebraic.Decorated.Functor.DecoratedFunctor W (alist) := DecoratedFunctor_zero. (** ** DTM instance *) (******************************************************************************) #[global] Instance DecoratedTraversableFunctor_alist : DecoratedTraversableFunctor W (alist). Proof. constructor. typeclasses eauto. typeclasses eauto. intros. unfold_ops @Dist_alist @Dist_compose. unfold_ops @Fmap_compose. unfold_ops @Decorate_alist @Decorate_zero. reassociate <-. change (fmap G (fmap (list ○ prod atom) ?f)) with (fmap (G ∘ list) (fmap (prod atom) f)). #[local] Set Keyed Unification. rewrite (natural (Natural := dist_natural list) (G := G ∘ list)). reassociate -> on right. rewrite (fun_fmap_fmap list). change (fmap list (fmap (prod atom) ?f)) with (fmap (list ∘ prod atom) f). (* rewrite <- (natural (Natural := dist_natural list) (G := G ∘ list)). rewrite (natural (Natural := dist_natural list)). rewrite (dist_natural (prod atom)). reassociate -> on left. rewrite (fun_fmap_fmap list). reassociate -> on left. rewrite (fun_fmap_fmap list). rewrite (fun_fmap_fmap (prod atom)). reflexivity. #[local] Unset Keyed Unification. *) Qed. *)EndDecoratedTraversableFunctor_alist.(** * <<envmap>> *)(******************************************************************************)(** [envmap] is just [fmap] specialized to <<alist>>. *)Definitionenvmap {AB } : (A -> B) -> alist A -> alist B :=
map (F := alist).(** ** Rewriting principles for [envmap] *)(******************************************************************************)Sectionenvmap_lemmas.Context
(AB : Type).Implicit Types (f : A -> B) (x : atom) (a : A) (Γ : list (atom * A)).
A, B: Type
forallf, envmap f [] = []
A, B: Type
forallf, envmap f [] = []
A, B: Type
forallf, map f [] = []
A, B: Type
forallf, map (map f) [] = []
now simpl_list.Qed.
A, B: Type
forallfxa, envmap f (x ~ a) = x ~ f a
A, B: Type
forallfxa, envmap f (x ~ a) = x ~ f a
reflexivity.Qed.
A, B: Type
forallfxaΓ,
envmap f ((x, a) :: Γ) = x ~ f a ++ envmap f Γ
A, B: Type
forallfxaΓ,
envmap f ((x, a) :: Γ) = x ~ f a ++ envmap f Γ
reflexivity.Qed.
A, B: Type
forallfΓ1Γ2,
envmap f (Γ1 ++ Γ2) = envmap f Γ1 ++ envmap f Γ2
A, B: Type
forallfΓ1Γ2,
envmap f (Γ1 ++ Γ2) = envmap f Γ1 ++ envmap f Γ2
now simpl_list.Qed.Endenvmap_lemmas.Create HintDb tea_rw_envmap.#[export] Hint Rewrite envmap_nil envmap_one
envmap_cons envmap_app : tea_rw_envmap.(** ** Specifications for [∈] and <<envmap>>*)(******************************************************************************)Sectionin_envmap_lemmas.Context
{AB : Type}
(l : alist A)
(f : A -> B).
A, B: Type l: alist A f: A -> B
forall (x : atom) (b : B),
(x, b) ∈ (envmap f l : list (atom * B)) <->
(existsa : A,
(x, a) ∈ (l : list (atom * A)) /\ f a = b)
A, B: Type l: alist A f: A -> B
forall (x : atom) (b : B),
(x, b) ∈ (envmap f l : list (atom * B)) <->
(existsa : A,
(x, a) ∈ (l : list (atom * A)) /\ f a = b)
A, B: Type l: alist A f: A -> B x: atom b: B
(x, b) ∈ (envmap f l : list (atom * B)) <->
(existsa : A,
(x, a) ∈ (l : list (atom * A)) /\ f a = b)
A, B: Type l: alist A f: A -> B x: atom b: B
(x, b) ∈ map f l <->
(existsa : A, (x, a) ∈ l /\ f a = b)
A, B: Type l: alist A f: A -> B x: atom b: B
(x, b) ∈ map (map_snd f) l <->
(existsa : A, (x, a) ∈ l /\ f a = b)
A, B: Type l: alist A f: A -> B x: atom b: B
(existsa : atom * A, a ∈ l /\ map_snd f a = (x, b)) <->
(existsa : A, (x, a) ∈ l /\ f a = b)
split; intros; preprocess; eauto.Qed.Endin_envmap_lemmas.(** ** Rewriting principles for [∈] *)(******************************************************************************)Sectionin_rewriting_lemmas.Context
(AB : Type).Implicit Types (x : atom) (a : A) (b : B).
forall (xy : atom) a1a2,
(x, a1) ∈ (y ~ a2) <-> x = y /\ a1 = a2
A, B: Type
forall (xy : atom) a1a2,
(x, a1) ∈ (y ~ a2) <-> x = y /\ a1 = a2
A, B: Type x, y: atom a1, a2: A
(x, a1) ∈ (y ~ a2) <-> x = y /\ a1 = a2
A, B: Type x, y: atom a1, a2: A
(x, a1) = (y, a2) <-> x = y /\ a1 = a2
nowrewrite pair_equal_spec.Qed.
A, B: Type
forallxa (Γ1Γ2 : list (atom * A)),
(x, a) ∈ (Γ1 ++ Γ2) <-> (x, a) ∈ Γ1 \/ (x, a) ∈ Γ2
A, B: Type
forallxa (Γ1Γ2 : list (atom * A)),
(x, a) ∈ (Γ1 ++ Γ2) <-> (x, a) ∈ Γ1 \/ (x, a) ∈ Γ2
A, B: Type x: atom a: A Γ1, Γ2: list (atom * A)
(x, a) ∈ (Γ1 ++ Γ2) <-> (x, a) ∈ Γ1 \/ (x, a) ∈ Γ2
nowautorewrite with tea_list.Qed.Endin_rewriting_lemmas.Create HintDb tea_rw_in.#[export] Hint Rewrite @in_nil_iff @in_cons_iff
@in_one_iff @in_app_iff @in_envmap_iff : tea_rw_in.(** ** Tactical lemmas for [∈] *)(******************************************************************************)Sectionin_theorems.Context
(AB : Type).Implicit Types (xy : atom) (ab : A) (f : A -> B) (Γ : list (atom * A)).
A, B: Type
forallxayb, (x, a) ∈ (y ~ b) -> x = y
A, B: Type
forallxayb, (x, a) ∈ (y ~ b) -> x = y
A, B: Type x: atom a: A y: atom b: A
(x, a) ∈ (y ~ b) -> x = y
nowautorewrite with tea_rw_in.Qed.
A, B: Type
forallxayb, (x, a) ∈ (y ~ b) -> a = b
A, B: Type
forallxayb, (x, a) ∈ (y ~ b) -> a = b
A, B: Type x: atom a: A y: atom b: A
(x, a) ∈ (y ~ b) -> a = b
nowautorewrite with tea_rw_in.Qed.
A, B: Type
forallxa, (x, a) ∈ (x ~ a)
A, B: Type
forallxa, (x, a) ∈ (x ~ a)
A, B: Type x: atom a: A
(x, a) ∈ (x ~ a)
nowautorewrite with tea_rw_in.Qed.
A, B: Type
forallxyabΓ,
(x, a) ∈ ((y, b) :: Γ) -> x = y /\ a = b \/ (x, a) ∈ Γ
A, B: Type
forallxyabΓ,
(x, a) ∈ ((y, b) :: Γ) -> x = y /\ a = b \/ (x, a) ∈ Γ
A, B: Type x, y: atom a, b: A Γ: list (atom * A)
(x, a) ∈ ((y, b) :: Γ) -> x = y /\ a = b \/ (x, a) ∈ Γ
nowautorewrite with tea_rw_in.Qed.
A, B: Type
forallxa (E : list (atom * A)),
(x, a) ∈ ((x, a) :: E)
A, B: Type
forallxa (E : list (atom * A)),
(x, a) ∈ ((x, a) :: E)
A, B: Type x: atom a: A E: list (atom * A)
(x, a) ∈ ((x, a) :: E)
A, B: Type x: atom a: A E: list (atom * A)
x = x /\ a = a \/ (x, a) ∈ E
nowleft.Qed.
A, B: Type
forallxayb (E : list (atom * A)),
(x, a) ∈ E -> (x, a) ∈ ((y, b) :: E)
A, B: Type
forallxayb (E : list (atom * A)),
(x, a) ∈ E -> (x, a) ∈ ((y, b) :: E)
A, B: Type x: atom a: A y: atom b: A E: list (atom * A) H: (x, a) ∈ E
(x, a) ∈ ((y, b) :: E)
A, B: Type x: atom a: A y: atom b: A E: list (atom * A) H: (x, a) ∈ E
x = y /\ a = b \/ (x, a) ∈ E
auto.Qed.
A, B: Type
forallxaΓ1Γ2, (x, a) ∈ Γ1 -> (x, a) ∈ (Γ1 ++ Γ2)
A, B: Type
forallxaΓ1Γ2, (x, a) ∈ Γ1 -> (x, a) ∈ (Γ1 ++ Γ2)
A, B: Type x: atom a: A Γ1, Γ2: list (atom * A) H: (x, a) ∈ Γ1
(x, a) ∈ (Γ1 ++ Γ2)
A, B: Type x: atom a: A Γ1, Γ2: list (atom * A) H: (x, a) ∈ Γ1
(x, a) ∈ Γ1 \/ (x, a) ∈ Γ2
auto.Qed.
A, B: Type
forallxaΓ1Γ2, (x, a) ∈ Γ2 -> (x, a) ∈ (Γ1 ++ Γ2)
A, B: Type
forallxaΓ1Γ2, (x, a) ∈ Γ2 -> (x, a) ∈ (Γ1 ++ Γ2)
A, B: Type x: atom a: A Γ1, Γ2: list (atom * A) H: (x, a) ∈ Γ2
(x, a) ∈ (Γ1 ++ Γ2)
A, B: Type x: atom a: A Γ1, Γ2: list (atom * A) H: (x, a) ∈ Γ2
(x, a) ∈ Γ1 \/ (x, a) ∈ Γ2
auto.Qed.
A, B: Type
forallxafΓ,
(x, a) ∈ Γ ->
(x, f a) ∈ (envmap f Γ : list (atom * B))
A, B: Type
forallxafΓ,
(x, a) ∈ Γ ->
(x, f a) ∈ (envmap f Γ : list (atom * B))
A, B: Type x: atom a: A f: A -> B Γ: list (atom * A) hyp: (x, a) ∈ Γ
(x, f a) ∈ envmap f Γ
A, B: Type x: atom a: A f: A -> B Γ: list (atom * A) hyp: (x, a) ∈ Γ
existsa0, (x, a0) ∈ Γ /\ f a0 = f a
eauto.Qed.Endin_theorems.#[export] Hint Resolve in_one_3 in_cons2 in_cons_3 in_app2
in_app_3 in_fmap_mono : tea_alist.#[export] Hint Immediate in_one1 in_one2 : tea_alist.(** * Domain and range on alists *)(******************************************************************************)(** [dom] computes the list of keys of an association list. *)Definitiondom {A} (Γ : alist A) : list atom :=
map fst Γ.(** [domset] computes the keys as an [AtomSet.t] for use with <<fsetdec>>. *)Definitiondomset {A} (Γ : alist A) : AtomSet.t :=
atoms (dom Γ).(** [range] computes the list of values of an association list. *)Definitionrange {A} ( Γ : alist A) : list A :=
map (extract (W := (atom ×))) Γ.(** ** Rewriting lemmas for [dom] *)(******************************************************************************)Sectiondom_lemmas.Context
(A : Type).
A: Type
dom [] = []
A: Type
dom [] = []
reflexivity.Qed.
A: Type
forall (x : atom) (a : A) (E : alist A),
dom ((x, a) :: E) = [x] ++ dom E
A: Type
forall (x : atom) (a : A) (E : alist A),
dom ((x, a) :: E) = [x] ++ dom E
reflexivity.Qed.
A: Type
forall (x : atom) (a : A), dom (x ~ a) = [x]
A: Type
forall (x : atom) (a : A), dom (x ~ a) = [x]
reflexivity.Qed.
A: Type
forallEF : alist A, dom (E ++ F) = dom E ++ dom F
A: Type
forallEF : alist A, dom (E ++ F) = dom E ++ dom F
A: Type E, F: alist A
dom (E ++ F) = dom E ++ dom F
A: Type E, F: alist A
map fst (E ++ F) = map fst E ++ map fst F
now simpl_list.Qed.
A: Type
forall (B : Type) (f : A -> B) (l : alist A),
dom (envmap f l) = dom l
A: Type
forall (B : Type) (f : A -> B) (l : alist A),
dom (envmap f l) = dom l
A, B: Type f: A -> B l: alist A
dom (envmap f l) = dom l
A, B: Type f: A -> B l: alist A
map fst (map f l) = map fst l
A, B: Type f: A -> B l: alist A
(map fst ∘ map f) l = map fst l
A, B: Type f: A -> B l: alist A
(map fst ∘ map (map f)) l = map fst l
A, B: Type f: A -> B l: alist A
(map fst ∘ map (map f)) l = map fst l
A, B: Type f: A -> B l: alist A
map (fst ∘ map f) l = map fst l
A, B: Type f: A -> B l: alist A
fst ∘ map f = fst
now ext [? ?].Qed.Enddom_lemmas.Create HintDb tea_rw_dom.#[export] Hint Rewrite dom_nil dom_cons dom_app dom_one dom_map : tea_rw_dom.
forallPQ : Prop, ~ (P \/ Q) <-> ~ P /\ ~ Q
forallPQ : Prop, ~ (P \/ Q) <-> ~ P /\ ~ Q
firstorder.Qed.#[export] Hint Rewrite push_not : tea_rw_dom.(** ** Rewriting lemmas for [domset] *)(******************************************************************************)Sectiondomset_lemmas.Context
(A : Type).
A: Type
domset [] [=] ∅
A: Type
domset [] [=] ∅
reflexivity.Qed.
A: Type
forall (x : atom) (a : A) (Γ : alist A),
domset ((x, a) :: Γ) [=] {{x}} ∪ domset Γ
A: Type
forall (x : atom) (a : A) (Γ : alist A),
domset ((x, a) :: Γ) [=] {{x}} ∪ domset Γ
now ext [? ?].Qed.Endrange_lemmas.Create HintDb tea_rw_range.#[export] Hint Rewrite range_nil range_cons
range_one range_app range_map : tea_rw_range.(** ** Rewriting lemmas for [∈] [dom] *)(******************************************************************************)Sectionin_dom_lemmas.Context
(A : Type).
A: Type
forallx : atom, x ∈ dom [] <-> False
A: Type
forallx : atom, x ∈ dom [] <-> False
intros; nowautorewrite with tea_rw_dom.Qed.
A: Type
forall (xy : atom) (a : A) (Γ : alist A),
y ∈ dom ((x, a) :: Γ) <-> y = x \/ y ∈ dom Γ
A: Type
forall (xy : atom) (a : A) (Γ : alist A),
y ∈ dom ((x, a) :: Γ) <-> y = x \/ y ∈ dom Γ
A: Type x, y: atom a: A Γ: alist A
y ∈ ([x] ++ dom Γ) <-> y = x \/ y ∈ dom Γ
A: Type x, y: atom a: A Γ: alist A
y ∈ [x] \/ y ∈ dom Γ <-> y = x \/ y ∈ dom Γ
A: Type x, y: atom a: A Γ: alist A
y = x \/ y ∈ dom Γ <-> y = x \/ y ∈ dom Γ
reflexivity.Qed.
A: Type
forall (xy : atom) (a : A), y ∈ dom (x ~ a) <-> y = x
A: Type
forall (xy : atom) (a : A), y ∈ dom (x ~ a) <-> y = x
A: Type x, y: atom a: A
y ∈ dom (x ~ a) <-> y = x
nowautorewrite with tea_rw_dom tea_list.Qed.
A: Type
forall (x : atom) (Γ1Γ2 : alist A),
x ∈ dom (Γ1 ++ Γ2) <-> x ∈ dom Γ1 \/ x ∈ dom Γ2
A: Type
forall (x : atom) (Γ1Γ2 : alist A),
x ∈ dom (Γ1 ++ Γ2) <-> x ∈ dom Γ1 \/ x ∈ dom Γ2
intros; nowautorewrite with tea_rw_dom tea_list.Qed.
A: Type
forall (B : Type) (f : A -> B) (Γ : alist A)
(x : atom), x ∈ dom (envmap f Γ) <-> x ∈ dom Γ
A: Type
forall (B : Type) (f : A -> B) (Γ : alist A)
(x : atom), x ∈ dom (envmap f Γ) <-> x ∈ dom Γ
intros; nowautorewrite with tea_rw_dom.Qed.Endin_dom_lemmas.#[export] Hint Rewrite in_dom_nil in_dom_one in_dom_cons
in_dom_app in_dom_map : tea_rw_dom.(** ** Rewriting lemmas for [∈] [domset] *)(******************************************************************************)Sectionin_domset_lemmas.Context
(A : Type).
A: Type
forallx : AtomSet.elt, x `in` domset [] <-> False
A: Type
forallx : AtomSet.elt, x `in` domset [] <-> False
A: Type x: AtomSet.elt
x `in` domset [] <-> False
A: Type x: AtomSet.elt
x `in` ∅ <-> False
fsetdec.Qed.
A: Type
forall (xy : atom) (a : A),
y `in` domset (x ~ a) <-> y = x
A: Type
forall (xy : atom) (a : A),
y `in` domset (x ~ a) <-> y = x
A: Type x, y: atom a: A
y `in` domset (x ~ a) <-> y = x
A: Type x, y: atom a: A
y `in` {{x}} <-> y = x
fsetdec.Qed.
A: Type
forall (xy : atom) (a : A) (Γ : alist A),
y `in` domset ((x, a) :: Γ) <->
y = x \/ y `in` domset Γ
A: Type
forall (xy : atom) (a : A) (Γ : alist A),
y `in` domset ((x, a) :: Γ) <->
y = x \/ y `in` domset Γ
A: Type x, y: atom a: A Γ: alist A
y `in` domset ((x, a) :: Γ) <->
y = x \/ y `in` domset Γ
A: Type x, y: atom a: A Γ: alist A
y `in` ({{x}} ∪ domset Γ) <-> y = x \/ y `in` domset Γ
fsetdec.Qed.
A: Type
forall (x : AtomSet.elt) (Γ1Γ2 : alist A),
x `in` domset (Γ1 ++ Γ2) <->
x `in` domset Γ1 \/ x `in` domset Γ2
A: Type
forall (x : AtomSet.elt) (Γ1Γ2 : alist A),
x `in` domset (Γ1 ++ Γ2) <->
x `in` domset Γ1 \/ x `in` domset Γ2
A: Type x: AtomSet.elt Γ1, Γ2: alist A
x `in` domset (Γ1 ++ Γ2) <->
x `in` domset Γ1 \/ x `in` domset Γ2
A: Type x: AtomSet.elt Γ1, Γ2: alist A
x `in` (domset Γ1 ∪ domset Γ2) <->
x `in` domset Γ1 \/ x `in` domset Γ2
fsetdec.Qed.
A: Type
forall (B : Type) (f : A -> B) (l : alist A)
(x : AtomSet.elt),
x `in` domset (envmap f l) <-> x `in` domset l
A: Type
forall (B : Type) (f : A -> B) (l : alist A)
(x : AtomSet.elt),
x `in` domset (envmap f l) <-> x `in` domset l
A, B: Type f: A -> B l: alist A x: AtomSet.elt
x `in` domset (envmap f l) <-> x `in` domset l
A, B: Type f: A -> B l: alist A x: AtomSet.elt
x `in` domset l <-> x `in` domset l
fsetdec.Qed.Endin_domset_lemmas.#[export] Hint Rewrite in_domset_nil in_domset_one
in_domset_cons in_domset_app in_domset_map : tea_rw_dom.(** ** Elements of [range] *)(******************************************************************************)Sectionin_range_lemmas.Context
(A : Type).
A: Type
forallx : A, x ∈ range [] <-> False
A: Type
forallx : A, x ∈ range [] <-> False
intros; nowautorewrite with tea_rw_range.Qed.
A: Type
forall (x : atom) (a1a2 : A) (Γ : alist A),
a2 ∈ range ((x, a1) :: Γ) <-> a2 = a1 \/ a2 ∈ range Γ
A: Type
forall (x : atom) (a1a2 : A) (Γ : alist A),
a2 ∈ range ((x, a1) :: Γ) <-> a2 = a1 \/ a2 ∈ range Γ
intros; nowautorewrite with tea_rw_range tea_list.Qed.
intros; nowautorewrite with tea_rw_range tea_list.Qed.
A: Type
forall (x : A) (Γ1Γ2 : alist A),
x ∈ range (Γ1 ++ Γ2) <-> x ∈ range Γ1 \/ x ∈ range Γ2
A: Type
forall (x : A) (Γ1Γ2 : alist A),
x ∈ range (Γ1 ++ Γ2) <-> x ∈ range Γ1 \/ x ∈ range Γ2
intros; nowautorewrite with tea_rw_range tea_list.Qed.
A: Type
forall (B : Type) (f : A -> B) (l : alist A) (b : B),
b ∈ range (envmap f l) <->
(existsa : A, a ∈ range l /\ f a = b)
A: Type
forall (B : Type) (f : A -> B) (l : alist A) (b : B),
b ∈ range (envmap f l) <->
(existsa : A, a ∈ range l /\ f a = b)
A, B: Type f: A -> B l: alist A b: B
b ∈ range (envmap f l) <->
(existsa : A, a ∈ range l /\ f a = b)
A, B: Type f: A -> B l: alist A b: B
b ∈ map f (range l) <->
(existsa : A, a ∈ range l /\ f a = b)
nowrewrite (in_map_iff list).Qed.Endin_range_lemmas.#[export] Hint Rewrite in_range_nil in_range_one
in_range_cons in_range_app in_range_map : tea_rw_range.(** * Specifications for operations on association lists *)(******************************************************************************)(** ** Specifications for <<∈>> and [dom], [domset], [range] *)(******************************************************************************)Sectionin_operations_lemmas.Context
{A : Type}
(Γ : alist A).Ltacauto_star ::= intro; preprocess; eauto.
A: Type Γ: alist A
forallx : atom,
x ∈ dom Γ <->
(existsa : A, (x, a) ∈ (Γ : list (atom * A)))
A: Type Γ: alist A
forallx : atom,
x ∈ dom Γ <->
(existsa : A, (x, a) ∈ (Γ : list (atom * A)))
A: Type Γ: alist A x: atom
x ∈ dom Γ <->
(existsa : A, (x, a) ∈ (Γ : list (atom * A)))
A: Type Γ: alist A x: atom
x ∈ map fst Γ <-> (existsa : A, (x, a) ∈ Γ)
A: Type Γ: alist A x: atom
(existsa : atom * A, a ∈ Γ /\ fst a = x) <->
(existsa : A, (x, a) ∈ Γ)
splits*.Qed.
A: Type Γ: alist A
foralla : A,
a ∈ range Γ <->
(existsx : atom, (x, a) ∈ (Γ : list (atom * A)))
A: Type Γ: alist A
foralla : A,
a ∈ range Γ <->
(existsx : atom, (x, a) ∈ (Γ : list (atom * A)))
A: Type Γ: alist A a: A
a ∈ range Γ <->
(existsx : atom, (x, a) ∈ (Γ : list (atom * A)))
A: Type Γ: alist A a: A
a ∈ map extract Γ <-> (existsx : atom, (x, a) ∈ Γ)
A: Type Γ: alist A a: A
(existsa0 : atom * A, a0 ∈ Γ /\ extract a0 = a) <->
(existsx : atom, (x, a) ∈ Γ)
splits*.Qed.
A: Type Γ: alist A
forallx : AtomSet.elt,
x `in` domset Γ <->
(existsa : A, (x, a) ∈ (Γ : list (atom * A)))
A: Type Γ: alist A
forallx : AtomSet.elt,
x `in` domset Γ <->
(existsa : A, (x, a) ∈ (Γ : list (atom * A)))
A: Type Γ: alist A
forallx : AtomSet.elt,
x `in` atoms (dom Γ) <-> (existsa : A, (x, a) ∈ Γ)
A: Type Γ: alist A x: AtomSet.elt
x `in` atoms (dom Γ) <-> (existsa : A, (x, a) ∈ Γ)
A: Type Γ: alist A x: AtomSet.elt
x ∈ dom Γ <-> (existsa : A, (x, a) ∈ Γ)
A: Type Γ: alist A x: AtomSet.elt
(existsa : A, (x, a) ∈ Γ) <->
(existsa : A, (x, a) ∈ Γ)
easy.Qed.
A: Type Γ: alist A
forallx : AtomSet.elt, x `in` domset Γ <-> x ∈ dom Γ
A: Type Γ: alist A
forallx : AtomSet.elt, x `in` domset Γ <-> x ∈ dom Γ
A: Type Γ: alist A x: AtomSet.elt
x `in` domset Γ <-> x ∈ dom Γ
A: Type Γ: alist A x: AtomSet.elt
(existsa : A, (x, a) ∈ Γ) <-> x ∈ dom Γ
A: Type Γ: alist A x: AtomSet.elt
(existsa : A, (x, a) ∈ Γ) <->
(existsa : A, (x, a) ∈ Γ)
easy.Qed.Endin_operations_lemmas.Sectionin_envmap_lemmas.Context
{AB : Type}
(l : alist A)
(f : A -> B).
A, B: Type l: alist A f: A -> B
forallb : B,
b ∈ range (envmap f l) <->
(existsa : A, a ∈ range l /\ f a = b)
A, B: Type l: alist A f: A -> B
forallb : B,
b ∈ range (envmap f l) <->
(existsa : A, a ∈ range l /\ f a = b)
A, B: Type l: alist A f: A -> B b: B
b ∈ range (envmap f l) <->
(existsa : A, a ∈ range l /\ f a = b)
A, B: Type l: alist A f: A -> B b: B
(existsx : atom, (x, b) ∈ envmap f l) <->
(existsa : A,
(existsx : atom, (x, a) ∈ l) /\ f a = b)
A, B: Type l: alist A f: A -> B b: B
(exists (x : atom) (a : A), (x, a) ∈ l /\ f a = b) <->
(existsa : A,
(existsx : atom, (x, a) ∈ l) /\ f a = b)
firstorder.Qed.
A, B: Type l: alist A f: A -> B
forallx : atom, x ∈ dom (envmap f l) <-> x ∈ dom l
A, B: Type l: alist A f: A -> B
forallx : atom, x ∈ dom (envmap f l) <-> x ∈ dom l
A, B: Type l: alist A f: A -> B x: atom
x ∈ dom (envmap f l) <-> x ∈ dom l
A, B: Type l: alist A f: A -> B x: atom
(existsa : B, (x, a) ∈ envmap f l) <->
(existsa : A, (x, a) ∈ l)
A, B: Type l: alist A f: A -> B x: atom
(exists (a : B) (a0 : A), (x, a0) ∈ l /\ f a0 = a) <->
(existsa : A, (x, a) ∈ l)
firstordereauto.Qed.Endin_envmap_lemmas.Sectionin_in.Context (AB : Type).Implicit Types (x : atom) (a : A) (b : B).
A, B: Type
forallxa (Γ : list (atom * A)),
(x, a) ∈ Γ -> x ∈ dom Γ
A, B: Type
forallxa (Γ : list (atom * A)),
(x, a) ∈ Γ -> x ∈ dom Γ
A, B: Type
forallxa (Γ : list (atom * A)),
(x, a) ∈ Γ -> existsa0, (x, a0) ∈ Γ
eauto.Qed.
A, B: Type
forallxa (Γ : list (atom * A)),
(x, a) ∈ Γ -> x `in` domset Γ
A, B: Type
forallxa (Γ : list (atom * A)),
(x, a) ∈ Γ -> x `in` domset Γ
A, B: Type
forallxa (Γ : list (atom * A)),
(x, a) ∈ Γ -> existsa0, (x, a0) ∈ Γ
eauto.Qed.
A, B: Type
forallxa (Γ : list (atom * A)),
(x, a) ∈ Γ -> a ∈ range Γ
A, B: Type
forallxa (Γ : list (atom * A)),
(x, a) ∈ Γ -> a ∈ range Γ
A, B: Type
forallxa (Γ : list (atom * A)),
(x, a) ∈ Γ -> existsx0, (x0, a) ∈ Γ
eauto.Qed.Endin_in.#[export] Hint Immediate in_in_dom in_in_domset in_in_range : tea_alist.(** ** Support for prettifying association lists *)(** The following rewrite rules can be used for normalizing alists. Note that we prefer <<one x ++ l>> to <<cons x l>>. These rules are put into a rewrite hint database that can be invoked as <<simpl_alist>>. *)(******************************************************************************)Sectionalist_simpl_lemmas.VariableX : Type.Variablesx : X.Variablesll1l2l3 : list X.
X: Type x: X l, l1, l2, l3: list X
x :: l = one x ++ l
X: Type x: X l, l1, l2, l3: list X
x :: l = one x ++ l
X: Type x: X l: list X
x :: l = one x ++ l
reflexivity.Qed.
X: Type x: X l, l1, l2, l3: list X
(x :: l1) ++ l2 = x :: l1 ++ l2
X: Type x: X l, l1, l2, l3: list X
(x :: l1) ++ l2 = x :: l1 ++ l2
X: Type x: X l1, l2: list X
(x :: l1) ++ l2 = x :: l1 ++ l2
reflexivity.Qed.
X: Type x: X l, l1, l2, l3: list X
(l1 ++ l2) ++ l3 = l1 ++ l2 ++ l3
X: Type x: X l, l1, l2, l3: list X
(l1 ++ l2) ++ l3 = l1 ++ l2 ++ l3
X: Type l1, l2, l3: list X
(l1 ++ l2) ++ l3 = l1 ++ l2 ++ l3
auto with datatypes.Qed.
X: Type x: X l, l1, l2, l3: list X
[] ++ l = l
X: Type x: X l, l1, l2, l3: list X
[] ++ l = l
X: Type l: list X
[] ++ l = l
reflexivity.Qed.
X: Type x: X l, l1, l2, l3: list X
l ++ [] = l
X: Type x: X l, l1, l2, l3: list X
l ++ [] = l
X: Type l: list X
l ++ [] = l
auto with datatypes.Qed.Endalist_simpl_lemmas.Create HintDb tea_simpl_alist.#[export] Hint Rewrite cons_app_one cons_app_assoc : tea_simpl_alist.#[export] Hint Rewrite app_assoc app_nil_l app_nil_r : tea_simpl_alist.Ltacsimpl_alist :=
autorewrite with tea_simpl_alist.Tactic Notation"simpl_alist""in" hyp(H) :=
autorewrite with tea_simpl_alist in H.Tactic Notation"simpl_alist""in""*" :=
autorewrite with tea_simpl_alist in *.(** ** Tactics for normalizing alists *)(******************************************************************************)(** The tactic <<change_alist>> can be used to replace an alist with an equivalent form, as long as the two forms are equal after normalizing with <<simpl_alist>>. *)Tactic Notation"change_alist"constr(E) :=
match goal with
| |- context[?x] =>
change x with E
| |- context[?x] =>
replace x with E;
[| simpl_alist; reflexivity ]
end.Tactic Notation"change_alist"constr(E) "in" hyp(H) :=
matchtype of H with
| context[?x] =>
change x with E in H
| context[?x] =>
replace x with E in H;
[| simpl_alist; reflexivity ]
end.(** ** Induction principles for alists *)(** The tactic <<alist induction>> can be used for induction onalists. The difference between this and ordinary induction on lists isthat the induction hypothesis is stated in terms of <<one>> and <<++>>rather than <<cons>>.*)(******************************************************************************)
forall (A : Type) (P : alist A -> Type),
P [] ->
(forall (x : atom) (a : A) (xs : alist A),
P xs -> P (x ~ a ++ xs)) -> forallxs : alist A, P xs
forall (A : Type) (P : alist A -> Type),
P [] ->
(forall (x : atom) (a : A) (xs : alist A),
P xs -> P (x ~ a ++ xs)) -> forallxs : alist A, P xs
A: Type P: alist A -> Type X: P [] X0: forall (x : atom) (a : A) (xs : alist A),
P xs -> P (x ~ a ++ xs)
P []
A: Type P: alist A -> Type X: P [] X0: forall (x : atom) (a : A) (xs : alist A),
P xs -> P (x ~ a ++ xs) x: atom a: A xs: list (atom * A) IHxs: P xs
P ((x, a) :: xs)
A: Type P: alist A -> Type X: P [] X0: forall (x : atom) (a : A) (xs : alist A),
P xs -> P (x ~ a ++ xs) x: atom a: A xs: list (atom * A) IHxs: P xs
P ((x, a) :: xs)
A: Type P: alist A -> Type X: P [] X0: forall (x : atom) (a : A) (xs : alist A),
P xs -> P (x ~ a ++ xs) x: atom a: A xs: list (atom * A) IHxs: P xs
P (x ~ a ++ xs)
auto.Defined.Tactic Notation"alist""induction"ident(E) :=
try (intros until E);
letT := type of E inletT := evalcomputein T inmatch T with
| list (?key * ?A) => induction E using (alist_ind A)
end.Tactic Notation"alist""induction"ident(E) "as" simple_intropattern(P) :=
try (intros until E);
letT := type of E inletT := evalcomputein T inmatch T with
| list (?key * ?A) => induction E as P using (alist_ind A)
end.(** <<uniq l>> whenever the keys of <<l>> contain no duplicates. *)Inductiveuniq {A} : alist A -> Prop :=
| uniq_nil : uniq nil
| uniq_push : forall (x : atom) (v : A) ( Γ : alist A),
uniq Γ -> ~ x `in` domset Γ -> uniq (x ~ v ++ Γ).(** <<disjoint E F>> whenever the keys of <<E>> and <<F>> contain nocommon elements. *)Definitiondisjoint {AB} (Γ1 : alist A) (Γ2 : alist B) :=
domset Γ1 ∩ domset Γ2 [=] ∅.(** ** Rewriting principles for [disjoint] *)(******************************************************************************)Sectiondisjoint_rewriting_lemmas.Context
(ABC : Type).
forall (Γ1 : alist A) (Γ2 : alist B) (f : A -> C),
disjoint (envmap f Γ1) Γ2 -> disjoint Γ1 Γ2
A, B, C: Type
forall (Γ1 : alist A) (Γ2 : alist B) (f : A -> C),
disjoint (envmap f Γ1) Γ2 -> disjoint Γ1 Γ2
A, B, C: Type Γ1: alist A Γ2: alist B f: A -> C
disjoint (envmap f Γ1) Γ2 -> disjoint Γ1 Γ2
nowautorewrite with tea_rw_disj.Qed.
A, B, C: Type
forall (Γ1 : alist A) (Γ2 : alist B) (f : A -> C),
disjoint Γ1 Γ2 -> disjoint (envmap f Γ1) Γ2
A, B, C: Type
forall (Γ1 : alist A) (Γ2 : alist B) (f : A -> C),
disjoint Γ1 Γ2 -> disjoint (envmap f Γ1) Γ2
A, B, C: Type Γ1: alist A Γ2: alist B f: A -> C
disjoint Γ1 Γ2 -> disjoint (envmap f Γ1) Γ2
nowautorewrite with tea_rw_disj.Qed.
A, B, C: Type
forall (x : atom) a (Γ : alist B),
disjoint (x ~ a) Γ -> x `notin` domset Γ
A, B, C: Type
forall (x : atom) a (Γ : alist B),
disjoint (x ~ a) Γ -> x `notin` domset Γ
A, B, C: Type x: atom a: A Γ: alist B
disjoint (x ~ a) Γ -> x `notin` domset Γ
nowautorewrite with tea_rw_disj.Qed.
A, B, C: Type
forall (x : AtomSet.elt) a (Γ : alist B),
x `notin` domset Γ -> disjoint (x ~ a) Γ
A, B, C: Type
forall (x : AtomSet.elt) a (Γ : alist B),
x `notin` domset Γ -> disjoint (x ~ a) Γ
A, B, C: Type x: AtomSet.elt a: A Γ: alist B
x `notin` domset Γ -> disjoint (x ~ a) Γ
nowautorewrite with tea_rw_disj.Qed.
A, B, C: Type
forall (x : atom) a (Γ1 : alist A) (Γ2 : alist B),
disjoint ((x, a) :: Γ1) Γ2 -> x `notin` domset Γ2
A, B, C: Type
forall (x : atom) a (Γ1 : alist A) (Γ2 : alist B),
disjoint ((x, a) :: Γ1) Γ2 -> x `notin` domset Γ2
A, B, C: Type x: atom a: A Γ1: alist A Γ2: alist B
disjoint ((x, a) :: Γ1) Γ2 -> x `notin` domset Γ2
nowautorewrite with tea_rw_disj.Qed.
A, B, C: Type
forall (x : atom) a (Γ1 : alist A) (Γ2 : alist B),
disjoint (x ~ a ++ Γ1) Γ2 -> x `notin` domset Γ2
A, B, C: Type
forall (x : atom) a (Γ1 : alist A) (Γ2 : alist B),
disjoint (x ~ a ++ Γ1) Γ2 -> x `notin` domset Γ2
A, B, C: Type x: atom a: A Γ1: alist A Γ2: alist B
disjoint (x ~ a ++ Γ1) Γ2 -> x `notin` domset Γ2
nowautorewrite with tea_rw_disj.Qed.
A, B, C: Type
forall (x : atom) a (Γ1 : alist A) (Γ2 : alist B),
disjoint ((x, a) :: Γ1) Γ2 -> disjoint Γ1 Γ2
A, B, C: Type
forall (x : atom) a (Γ1 : alist A) (Γ2 : alist B),
disjoint ((x, a) :: Γ1) Γ2 -> disjoint Γ1 Γ2
A, B, C: Type x: atom a: A Γ1: alist A Γ2: alist B
disjoint ((x, a) :: Γ1) Γ2 -> disjoint Γ1 Γ2
nowautorewrite with tea_rw_disj.Qed.
A, B, C: Type
forall (x : AtomSet.elt) (Γ1 : alist A) (Γ2 : alist B),
disjoint Γ1 Γ2 ->
x `in` domset Γ1 -> x `notin` domset Γ2
A, B, C: Type
forall (x : AtomSet.elt) (Γ1 : alist A) (Γ2 : alist B),
disjoint Γ1 Γ2 ->
x `in` domset Γ1 -> x `notin` domset Γ2
A, B, C: Type
forall (x : AtomSet.elt) (Γ1 : alist A) (Γ2 : alist B),
domset Γ1 ∩ domset Γ2 [=] ∅ ->
x `in` domset Γ1 -> x `notin` domset Γ2
fsetdec.Qed.
A, B, C: Type
forall (x : AtomSet.elt) (Γ1 : alist A) (Γ2 : alist B),
disjoint Γ1 Γ2 ->
x `in` domset Γ2 -> x `notin` domset Γ1
A, B, C: Type
forall (x : AtomSet.elt) (Γ1 : alist A) (Γ2 : alist B),
disjoint Γ1 Γ2 ->
x `in` domset Γ2 -> x `notin` domset Γ1
A, B, C: Type
forall (x : AtomSet.elt) (Γ1 : alist A) (Γ2 : alist B),
domset Γ1 ∩ domset Γ2 [=] ∅ ->
x `in` domset Γ2 -> x `notin` domset Γ1
fsetdec.Qed.
A, B, C: Type
forall (x : atom) a (Γ1Γ2 : alist A),
disjoint Γ1 Γ2 ->
(x, a) ∈ (Γ1 : list (atom * A)) ->
~ (x, a) ∈ (Γ2 : list (atom * A))
A, B, C: Type
forall (x : atom) a (Γ1Γ2 : alist A),
disjoint Γ1 Γ2 ->
(x, a) ∈ (Γ1 : list (atom * A)) ->
~ (x, a) ∈ (Γ2 : list (atom * A))
A, B, C: Type x: atom a: A Γ1, Γ2: alist A Hdisj: disjoint Γ1 Γ2 He: (x, a) ∈ Γ1 Hf: (x, a) ∈ Γ2
False
A, B, C: Type x: atom a: A Γ1, Γ2: alist A Hdisj: disjoint Γ1 Γ2 He: x `in` domset Γ1 Hf: (x, a) ∈ Γ2
False
A, B, C: Type x: atom a: A Γ1, Γ2: alist A Hdisj: disjoint Γ1 Γ2 He: x `in` domset Γ1 Hf: x `in` domset Γ2
False
A, B, C: Type x: atom a: A Γ1, Γ2: alist A Hdisj: domset Γ1 ∩ domset Γ2 [=] ∅ He: x `in` domset Γ1 Hf: x `in` domset Γ2
False
fsetdec.Qed.
A, B, C: Type
forall (x : atom) a (Γ1Γ2 : alist A),
disjoint Γ1 Γ2 ->
(x, a) ∈ (Γ1 : list (atom * A)) ->
~ (x, a) ∈ (Γ2 : list (atom * A))
A, B, C: Type
forall (x : atom) a (Γ1Γ2 : alist A),
disjoint Γ1 Γ2 ->
(x, a) ∈ (Γ1 : list (atom * A)) ->
~ (x, a) ∈ (Γ2 : list (atom * A))
A, B, C: Type x: atom a: A Γ1, Γ2: alist A Hd: disjoint Γ1 Γ2 Hf: (x, a) ∈ Γ1
~ (x, a) ∈ Γ2
eauto using disjoint_binds1.Qed.Enddisjoint_auto_lemmas.#[export] Hint Resolve disjoint_sym1 disjoint_app_3
disjoint_envmap2 : tea_alist.(** These introduce existential variables, so onlyapply them if they immediately solve the goal. *)#[export] Hint Immediate disjoint_app1 disjoint_app2
disjoint_one_l1 disjoint_envmap1
disjoint_dom1 disjoint_dom2
disjoint_binds1 disjoint_binds2 : tea_alist.(** ** Tactical lemmas for [uniq] *)(** For automating proofs about uniqueness, it is typically easier towork with (one-way) lemmas rather than rewriting principles, incontrast to most of the other parts of Tealeaves internals. *)(******************************************************************************)Sectionuniq_auto_lemmas.Context
(AB : Type)
(Γ1Γ2 : alist A).Implicit Types (x : atom) (a : A) (b : B).
A, B: Type Γ1, Γ2: alist A
forallxa, uniq (x ~ a)
A, B: Type Γ1, Γ2: alist A
forallxa, uniq (x ~ a)
A, B: Type Γ1, Γ2: alist A x: atom a: A
uniq (x ~ a)
A, B: Type Γ1, Γ2: alist A x: atom a: A
uniq (x ~ a ++ [])
constructor; [constructor | fsetdec].Qed.
A, B: Type Γ1, Γ2: alist A
forallxa, uniq ((x, a) :: Γ1) -> uniq Γ1
A, B: Type Γ1, Γ2: alist A
forallxa, uniq ((x, a) :: Γ1) -> uniq Γ1
nowinversion1.Qed.
A, B: Type Γ1, Γ2: alist A
forallxa, uniq ((x, a) :: Γ1) -> x `notin` domset Γ1
A, B: Type Γ1, Γ2: alist A
forallxa, uniq ((x, a) :: Γ1) -> x `notin` domset Γ1
nowinversion1.Qed.
A, B: Type Γ1, Γ2: alist A
forallxa,
x `notin` domset Γ1 -> uniq Γ1 -> uniq ((x, a) :: Γ1)
A, B: Type Γ1, Γ2: alist A
forallxa,
x `notin` domset Γ1 -> uniq Γ1 -> uniq ((x, a) :: Γ1)
A, B: Type Γ1, Γ2: alist A x: atom a: A H: x `notin` domset Γ1 H0: uniq Γ1
uniq ((x, a) :: Γ1)
constructor; auto.Qed.
A, B: Type Γ1, Γ2: alist A
uniq (Γ1 ++ Γ2) -> uniq Γ1
A, B: Type Γ1, Γ2: alist A
uniq (Γ1 ++ Γ2) -> uniq Γ1
A, B: Type Γ1, Γ2: alist A Hu: uniq (Γ1 ++ Γ2)
uniq Γ1
A, B: Type Γ1, Γ2: alist A Hu: uniq ([] ++ Γ2)
uniq []
A, B: Type Γ1, Γ2: alist A x: atom a: A a0: alist A Hu: uniq ((x ~ a ++ a0) ++ Γ2) IHa: uniq (a0 ++ Γ2) -> uniq a0
uniq (x ~ a ++ a0)
A, B: Type Γ1, Γ2: alist A Hu: uniq ([] ++ Γ2)
uniq []
constructor.
A, B: Type Γ1, Γ2: alist A x: atom a: A a0: alist A Hu: uniq ((x ~ a ++ a0) ++ Γ2) IHa: uniq (a0 ++ Γ2) -> uniq a0
uniq (x ~ a ++ a0)
A, B: Type Γ1, Γ2: alist A x: atom a: A a0: alist A Hu: uniq (x ~ a ++ a0 ++ Γ2) IHa: uniq (a0 ++ Γ2) -> uniq a0
uniq (x ~ a ++ a0)
A, B: Type Γ1, Γ2: alist A x: atom a: A a0: alist A IHa: uniq (a0 ++ Γ2) -> uniq a0 H1: uniq (a0 ++ Γ2) H3: x `notin` domset (a0 ++ Γ2)
uniq (x ~ a ++ a0)
A, B: Type Γ1, Γ2: alist A x: atom a: A a0: alist A IHa: uniq (a0 ++ Γ2) -> uniq a0 H1: uniq (a0 ++ Γ2) H3: x `notin` domset a0 /\ x `notin` domset Γ2
uniq (x ~ a ++ a0)
constructor; tauto.Qed.
A, B: Type Γ1, Γ2: alist A
uniq (Γ1 ++ Γ2) -> uniq Γ2
A, B: Type Γ1, Γ2: alist A
uniq (Γ1 ++ Γ2) -> uniq Γ2
A, B: Type Γ1, Γ2: alist A Hu: uniq (Γ1 ++ Γ2)
uniq Γ2
A, B: Type Γ1, Γ2: alist A Hu: uniq ([] ++ Γ2)
uniq Γ2
A, B: Type Γ1, Γ2: alist A x: atom a: A a0: alist A Hu: uniq ((x ~ a ++ a0) ++ Γ2) IHa: uniq (a0 ++ Γ2) -> uniq Γ2
uniq Γ2
A, B: Type Γ1, Γ2: alist A Hu: uniq ([] ++ Γ2)
uniq Γ2
trivial.
A, B: Type Γ1, Γ2: alist A x: atom a: A a0: alist A Hu: uniq ((x ~ a ++ a0) ++ Γ2) IHa: uniq (a0 ++ Γ2) -> uniq Γ2
uniq Γ2
A, B: Type Γ1, Γ2: alist A x: atom a: A a0: alist A IHa: uniq (a0 ++ Γ2) -> uniq Γ2 H1: uniq (a0 ++ Γ2) H3: x `notin` domset (a0 ++ Γ2)
uniq Γ2
auto.Qed.
A, B: Type Γ1, Γ2: alist A
uniq (Γ1 ++ Γ2) -> disjoint Γ1 Γ2
A, B: Type Γ1, Γ2: alist A
uniq (Γ1 ++ Γ2) -> disjoint Γ1 Γ2
A, B: Type Γ1, Γ2: alist A Hu: uniq (Γ1 ++ Γ2)
disjoint Γ1 Γ2
A, B: Type Γ1, Γ2: alist A Hu: uniq (Γ1 ++ Γ2)
domset Γ1 ∩ domset Γ2 [=] ∅
A, B: Type Γ1, Γ2: alist A Hu: uniq ([] ++ Γ2)
domset [] ∩ domset Γ2 [=] ∅
A, B: Type Γ1, Γ2: alist A x: atom a: A a0: alist A Hu: uniq ((x ~ a ++ a0) ++ Γ2) IH: uniq (a0 ++ Γ2) -> domset a0 ∩ domset Γ2 [=] ∅
domset (x ~ a ++ a0) ∩ domset Γ2 [=] ∅
A, B: Type Γ1, Γ2: alist A Hu: uniq ([] ++ Γ2)
domset [] ∩ domset Γ2 [=] ∅
fsetdec.
A, B: Type Γ1, Γ2: alist A x: atom a: A a0: alist A Hu: uniq ((x ~ a ++ a0) ++ Γ2) IH: uniq (a0 ++ Γ2) -> domset a0 ∩ domset Γ2 [=] ∅
domset (x ~ a ++ a0) ∩ domset Γ2 [=] ∅
A, B: Type Γ1, Γ2: alist A x: atom a: A a0: alist A IH: uniq (a0 ++ Γ2) -> domset a0 ∩ domset Γ2 [=] ∅ H1: uniq (a0 ++ Γ2) H3: x `notin` domset (a0 ++ Γ2)
domset (x ~ a ++ a0) ∩ domset Γ2 [=] ∅
A, B: Type Γ1, Γ2: alist A x: atom a: A a0: alist A IH: uniq (a0 ++ Γ2) -> domset a0 ∩ domset Γ2 [=] ∅ H1: uniq (a0 ++ Γ2) H3: x `notin` domset a0 /\ x `notin` domset Γ2
({{x}} ∪ domset a0) ∩ domset Γ2 [=] ∅
A, B: Type Γ1, Γ2: alist A x: atom a: A a0: alist A IH: uniq (a0 ++ Γ2) -> domset a0 ∩ domset Γ2 [=] ∅ H1: uniq (a0 ++ Γ2) H3: x `notin` domset a0 /\ x `notin` domset Γ2
A, B: Type Γ1, Γ2: alist A C: Type Γx, Γy: alist C H: uniq Γx H0: uniq Γy H1: disjoint Γx Γy
uniq (Γx ++ Γy)
A, B: Type Γ1, Γ2: alist A C: Type Γy: alist C H: uniq [] H0: uniq Γy H1: disjoint [] Γy
uniq ([] ++ Γy)
A, B: Type Γ1, Γ2: alist A C: Type Γy: alist C x: atom a: C Γz: alist C H: uniq (x ~ a ++ Γz) H0: uniq Γy H1: disjoint (x ~ a ++ Γz) Γy IHΓx: uniq Γz -> disjoint Γz Γy -> uniq (Γz ++ Γy)
uniq ((x ~ a ++ Γz) ++ Γy)
A, B: Type Γ1, Γ2: alist A C: Type Γy: alist C H: uniq [] H0: uniq Γy H1: disjoint [] Γy
uniq ([] ++ Γy)
A, B: Type Γ1, Γ2: alist A C: Type Γy: alist C H: uniq [] H0: uniq Γy H1: disjoint [] Γy
uniq Γy
assumption.
A, B: Type Γ1, Γ2: alist A C: Type Γy: alist C x: atom a: C Γz: alist C H: uniq (x ~ a ++ Γz) H0: uniq Γy H1: disjoint (x ~ a ++ Γz) Γy IHΓx: uniq Γz -> disjoint Γz Γy -> uniq (Γz ++ Γy)
uniq ((x ~ a ++ Γz) ++ Γy)
A, B: Type Γ1, Γ2: alist A C: Type Γy: alist C x: atom a: C Γz: alist C H: uniq (x ~ a ++ Γz) H0: uniq Γy H1: disjoint (x ~ a ++ Γz) Γy IHΓx: uniq Γz -> disjoint Γz Γy -> uniq (Γz ++ Γy)
uniq (x ~ a ++ Γz ++ Γy)
A, B: Type Γ1, Γ2: alist A C: Type Γy: alist C x: atom a: C Γz: alist C H0: uniq Γy H1: disjoint (x ~ a ++ Γz) Γy IHΓx: uniq Γz -> disjoint Γz Γy -> uniq (Γz ++ Γy) H4: uniq Γz H6: x `notin` domset Γz
uniq (x ~ a ++ Γz ++ Γy)
A, B: Type Γ1, Γ2: alist A C: Type Γy: alist C x: atom a: C Γz: alist C H0: uniq Γy H1: x `notin` domset Γy /\ disjoint Γz Γy IHΓx: uniq Γz -> disjoint Γz Γy -> uniq (Γz ++ Γy) H4: uniq Γz H6: x `notin` domset Γz
uniq (x ~ a ++ Γz ++ Γy)
A, B: Type Γ1, Γ2: alist A C: Type Γy: alist C x: atom a: C Γz: alist C H0: uniq Γy H1: x `notin` domset Γy /\ disjoint Γz Γy IHΓx: uniq Γz -> disjoint Γz Γy -> uniq (Γz ++ Γy) H4: uniq Γz H6: x `notin` domset Γz
uniq (Γz ++ Γy)
A, B: Type Γ1, Γ2: alist A C: Type Γy: alist C x: atom a: C Γz: alist C H0: uniq Γy H1: x `notin` domset Γy /\ disjoint Γz Γy IHΓx: uniq Γz -> disjoint Γz Γy -> uniq (Γz ++ Γy) H4: uniq Γz H6: x `notin` domset Γz
x `notin` domset (Γz ++ Γy)
A, B: Type Γ1, Γ2: alist A C: Type Γy: alist C x: atom a: C Γz: alist C H0: uniq Γy H1: x `notin` domset Γy /\ disjoint Γz Γy IHΓx: uniq Γz -> disjoint Γz Γy -> uniq (Γz ++ Γy) H4: uniq Γz H6: x `notin` domset Γz
uniq (Γz ++ Γy)
tauto.
A, B: Type Γ1, Γ2: alist A C: Type Γy: alist C x: atom a: C Γz: alist C H0: uniq Γy H1: x `notin` domset Γy /\ disjoint Γz Γy IHΓx: uniq Γz -> disjoint Γz Γy -> uniq (Γz ++ Γy) H4: uniq Γz H6: x `notin` domset Γz
x `notin` domset (Γz ++ Γy)
nowautorewrite with tea_rw_dom.Qed.
A, B: Type Γ1, Γ2: alist A
forallxa (Γ : list (atom * A)),
uniq (x ~ a ++ Γ) -> x `notin` domset Γ
A, B: Type Γ1, Γ2: alist A
forallxa (Γ : list (atom * A)),
uniq (x ~ a ++ Γ) -> x `notin` domset Γ
nowinversion1.Qed.(* For some reason, [uniq_app_4] will not be applied by auto on this goal. *)
A, B: Type Γ1, Γ2: alist A
uniq (Γ1 ++ Γ2) -> uniq (Γ2 ++ Γ1)
A, B: Type Γ1, Γ2: alist A
uniq (Γ1 ++ Γ2) -> uniq (Γ2 ++ Γ1)
A, B: Type Γ1, Γ2: alist A H: uniq (Γ1 ++ Γ2)
uniq (Γ2 ++ Γ1)
A, B: Type Γ1, Γ2: alist A H: uniq (Γ1 ++ Γ2)
uniq Γ2
A, B: Type Γ1, Γ2: alist A H: uniq (Γ1 ++ Γ2)
uniq Γ1
A, B: Type Γ1, Γ2: alist A H: uniq (Γ1 ++ Γ2)
disjoint Γ2 Γ1
all: eauto using uniq_app_4, uniq_app2,
uniq_app1, uniq_app_3, disjoint_sym1.Qed.
A, B: Type Γ1, Γ2: alist A
forallf : A -> B, uniq (envmap f Γ1) -> uniq Γ1
A, B: Type Γ1, Γ2: alist A
forallf : A -> B, uniq (envmap f Γ1) -> uniq Γ1
A, B: Type Γ1, Γ2: alist A f: A -> B Hu: uniq (envmap f Γ1)
uniq Γ1
A, B: Type Γ1, Γ2: alist A f: A -> B Hu: uniq (envmap f [])
uniq []
A, B: Type Γ1, Γ2: alist A f: A -> B x: atom a: A a0: alist A Hu: uniq (envmap f (x ~ a ++ a0)) IHa: uniq (envmap f a0) -> uniq a0
uniq (x ~ a ++ a0)
A, B: Type Γ1, Γ2: alist A f: A -> B Hu: uniq (envmap f [])
uniq []
constructor.
A, B: Type Γ1, Γ2: alist A f: A -> B x: atom a: A a0: alist A Hu: uniq (envmap f (x ~ a ++ a0)) IHa: uniq (envmap f a0) -> uniq a0
uniq (x ~ a ++ a0)
A, B: Type Γ1, Γ2: alist A f: A -> B x: atom a: A a0: alist A Hu: uniq (x ~ f a ++ envmap f a0) IHa: uniq (envmap f a0) -> uniq a0
uniq (x ~ a ++ a0)
A, B: Type Γ1, Γ2: alist A f: A -> B x: atom a: A a0: alist A IHa: uniq (envmap f a0) -> uniq a0 H1: uniq (envmap f a0) H3: x `notin` domset (envmap f a0)
uniq (x ~ a ++ a0)
A, B: Type Γ1, Γ2: alist A f: A -> B x: atom a: A a0: alist A IHa: uniq (envmap f a0) -> uniq a0 H1: uniq (envmap f a0) H3: x `notin` domset (envmap f a0)
uniq a0
A, B: Type Γ1, Γ2: alist A f: A -> B x: atom a: A a0: alist A IHa: uniq (envmap f a0) -> uniq a0 H1: uniq (envmap f a0) H3: x `notin` domset (envmap f a0)
x `notin` domset a0
A, B: Type Γ1, Γ2: alist A f: A -> B x: atom a: A a0: alist A IHa: uniq (envmap f a0) -> uniq a0 H1: uniq (envmap f a0) H3: x `notin` domset (envmap f a0)
uniq a0
auto.
A, B: Type Γ1, Γ2: alist A f: A -> B x: atom a: A a0: alist A IHa: uniq (envmap f a0) -> uniq a0 H1: uniq (envmap f a0) H3: x `notin` domset (envmap f a0)
x `notin` domset a0
nowautorewrite with tea_rw_dom in *.Qed.
A, B: Type Γ1, Γ2: alist A
forallf : A -> B, uniq Γ1 -> uniq (envmap f Γ1)
A, B: Type Γ1, Γ2: alist A
forallf : A -> B, uniq Γ1 -> uniq (envmap f Γ1)
A, B: Type Γ1, Γ2: alist A f: A -> B Hu: uniq Γ1
uniq (envmap f Γ1)
A, B: Type Γ1, Γ2: alist A f: A -> B Hu: uniq []
uniq (envmap f [])
A, B: Type Γ1, Γ2: alist A f: A -> B x: atom a: A a0: alist A Hu: uniq (x ~ a ++ a0) IHa: uniq a0 -> uniq (envmap f a0)
uniq (envmap f (x ~ a ++ a0))
A, B: Type Γ1, Γ2: alist A f: A -> B Hu: uniq []
uniq (envmap f [])
constructor.
A, B: Type Γ1, Γ2: alist A f: A -> B x: atom a: A a0: alist A Hu: uniq (x ~ a ++ a0) IHa: uniq a0 -> uniq (envmap f a0)
uniq (envmap f (x ~ a ++ a0))
A, B: Type Γ1, Γ2: alist A f: A -> B x: atom a: A a0: alist A Hu: uniq (x ~ a ++ a0) IHa: uniq a0 -> uniq (envmap f a0)
uniq (x ~ f a ++ envmap f a0)
A, B: Type Γ1, Γ2: alist A f: A -> B x: atom a: A a0: alist A IHa: uniq a0 -> uniq (envmap f a0) H1: uniq a0 H3: x `notin` domset a0
uniq (x ~ f a ++ envmap f a0)
A, B: Type Γ1, Γ2: alist A f: A -> B x: atom a: A a0: alist A IHa: uniq a0 -> uniq (envmap f a0) H1: uniq a0 H3: x `notin` domset a0
uniq (envmap f a0)
A, B: Type Γ1, Γ2: alist A f: A -> B x: atom a: A a0: alist A IHa: uniq a0 -> uniq (envmap f a0) H1: uniq a0 H3: x `notin` domset a0
x `notin` domset (envmap f a0)
A, B: Type Γ1, Γ2: alist A f: A -> B x: atom a: A a0: alist A IHa: uniq a0 -> uniq (envmap f a0) H1: uniq a0 H3: x `notin` domset a0
uniq (envmap f a0)
auto.
A, B: Type Γ1, Γ2: alist A f: A -> B x: atom a: A a0: alist A IHa: uniq a0 -> uniq (envmap f a0) H1: uniq a0 H3: x `notin` domset a0
x `notin` domset (envmap f a0)
nowautorewrite with tea_rw_dom in *.Qed.
A, B: Type Γ1, Γ2: alist A
forallf : A -> B, uniq (map f Γ1) -> uniq Γ1
A, B: Type Γ1, Γ2: alist A
forallf : A -> B, uniq (map f Γ1) -> uniq Γ1
A, B: Type Γ1, Γ2: alist A f: A -> B H: uniq (map f Γ1)
uniq Γ1
A, B: Type Γ1, Γ2: alist A f: A -> B H: uniq (map f Γ1)
uniq (envmap ?f Γ1)
exact H.Qed.
A, B: Type Γ1, Γ2: alist A
forallf : A -> B, uniq Γ1 -> uniq (map f Γ1)
A, B: Type Γ1, Γ2: alist A
forallf : A -> B, uniq Γ1 -> uniq (map f Γ1)
A, B: Type Γ1, Γ2: alist A f: A -> B H: uniq Γ1
uniq (map f Γ1)
nowapply uniq_envmap2.Qed.Enduniq_auto_lemmas.#[export] Hint Resolve uniq_nil uniq_push uniq_one
uniq_cons_3 uniq_app_3 uniq_app_4 uniq_envmap2 uniq_symm : tea_alist.(** These introduce existential variables *)#[export] Hint Immediate uniq_cons1
uniq_cons2 uniq_app1 uniq_app2
uniq_app_5 uniq_envmap1 : tea_alist.(** ** Rewriting principles for [uniq] *)(* *********************************************************************** *)Sectionuniq_rewriting_lemmas.Context
(AB : Type).Implicit Types (x : atom) (a : A) (b : B) (Γ : alist A).
A, B: Type
uniq ([] : list (atom * A)) <-> True
A, B: Type
uniq ([] : list (atom * A)) <-> True
split; auto with tea_alist.Qed.
A, B: Type
forallxaΓ,
uniq ((x, a) :: Γ) <-> x `notin` domset Γ /\ uniq Γ
A, B: Type
forallxaΓ,
uniq ((x, a) :: Γ) <-> x `notin` domset Γ /\ uniq Γ
A, B: Type x: atom a: A Γ: alist A
uniq ((x, a) :: Γ) -> x `notin` domset Γ /\ uniq Γ
A, B: Type x: atom a: A Γ: alist A
x `notin` domset Γ /\ uniq Γ -> uniq ((x, a) :: Γ)
A, B: Type x: atom a: A Γ: alist A
uniq ((x, a) :: Γ) -> x `notin` domset Γ /\ uniq Γ
eauto with tea_alist.
A, B: Type x: atom a: A Γ: alist A
x `notin` domset Γ /\ uniq Γ -> uniq ((x, a) :: Γ)
forallΓ1Γ2 (f : A -> A),
uniq (Γ1 ++ Γ2) -> uniq (envmap f Γ1 ++ Γ2)
A: Type
forallΓ1Γ2 (f : A -> A),
uniq (Γ1 ++ Γ2) -> uniq (envmap f Γ1 ++ Γ2)
A: Type Γ1, Γ2: list (atom * A) f: A -> A H: uniq (Γ1 ++ Γ2)
uniq (envmap f Γ1 ++ Γ2)
A: Type Γ1, Γ2: list (atom * A) f: A -> A H: uniq Γ1 /\ uniq Γ2 /\ disjoint Γ1 Γ2
uniq Γ1 /\ uniq Γ2 /\ disjoint Γ1 Γ2
tauto.Qed.
A: Type
forallxaΓ1Γ2,
uniq (Γ1 ++ x ~ a ++ Γ2) -> x `notin` domset Γ2
A: Type
forallxaΓ1Γ2,
uniq (Γ1 ++ x ~ a ++ Γ2) -> x `notin` domset Γ2
A: Type x: atom a: A Γ1, Γ2: list (atom * A) H: uniq (Γ1 ++ x ~ a ++ Γ2)
x `notin` domset Γ2
A: Type x: atom a: A Γ1, Γ2: list (atom * A) H: uniq Γ1 /\
(True /\ uniq Γ2 /\ x `notin` domset Γ2) /\
x `notin` domset Γ1 /\ disjoint Γ2 Γ1
x `notin` domset Γ2
tauto.Qed.
A: Type
forallxaΓ1Γ2,
uniq (Γ1 ++ x ~ a ++ Γ2) -> x `notin` domset Γ1
A: Type
forallxaΓ1Γ2,
uniq (Γ1 ++ x ~ a ++ Γ2) -> x `notin` domset Γ1
A: Type x: atom a: A Γ1, Γ2: list (atom * A) H: uniq (Γ1 ++ x ~ a ++ Γ2)
x `notin` domset Γ1
A: Type x: atom a: A Γ1, Γ2: list (atom * A) H: uniq Γ1 /\
(True /\ uniq Γ2 /\ x `notin` domset Γ2) /\
x `notin` domset Γ1 /\ disjoint Γ2 Γ1
x `notin` domset Γ1
tauto.Qed.Enduniq_theorems.(** ** Stronger theorems for <<∈>> on [uniq] lists *)(******************************************************************************)Sectionin_theorems_uniq.Context
(AB : Type).Implicit Types (x : atom) (a : A) (b : B).
A, B: Type
forallxa (Γ1Γ2 : list (atom * A)),
uniq (Γ1 ++ Γ2) ->
(x, a) ∈ (Γ1 ++ Γ2) <->
(x, a) ∈ Γ1 /\ x `notin` domset Γ2 \/
(x, a) ∈ Γ2 /\ x `notin` domset Γ1
A, B: Type
forallxa (Γ1Γ2 : list (atom * A)),
uniq (Γ1 ++ Γ2) ->
(x, a) ∈ (Γ1 ++ Γ2) <->
(x, a) ∈ Γ1 /\ x `notin` domset Γ2 \/
(x, a) ∈ Γ2 /\ x `notin` domset Γ1
A, B: Type x: atom a: A Γ1, Γ2: list (atom * A) H: uniq (Γ1 ++ Γ2)
(x, a) ∈ (Γ1 ++ Γ2) <->
(x, a) ∈ Γ1 /\ x `notin` domset Γ2 \/
(x, a) ∈ Γ2 /\ x `notin` domset Γ1
A, B: Type x: atom a: A Γ1, Γ2: list (atom * A) H: uniq Γ1 /\ uniq Γ2 /\ disjoint Γ1 Γ2
(x, a) ∈ Γ1 \/ (x, a) ∈ Γ2 <->
(x, a) ∈ Γ1 /\ x `notin` domset Γ2 \/
(x, a) ∈ Γ2 /\ x `notin` domset Γ1
A, B: Type x: atom a: A Γ1, Γ2: list (atom * A) H: uniq Γ1 H0: uniq Γ2 H1: disjoint Γ1 Γ2
(x, a) ∈ Γ1 \/ (x, a) ∈ Γ2 <->
(x, a) ∈ Γ1 /\ x `notin` domset Γ2 \/
(x, a) ∈ Γ2 /\ x `notin` domset Γ1
A, B: Type x: atom a: A Γ1, Γ2: list (atom * A) H: uniq Γ1 H0: uniq Γ2 H1: disjoint Γ1 Γ2
(x, a) ∈ Γ1 \/ (x, a) ∈ Γ2 ->
(x, a) ∈ Γ1 /\ x `notin` domset Γ2 \/
(x, a) ∈ Γ2 /\ x `notin` domset Γ1
A, B: Type x: atom a: A Γ1, Γ2: list (atom * A) H: uniq Γ1 H0: uniq Γ2 H1: disjoint Γ1 Γ2
(x, a) ∈ Γ1 /\ x `notin` domset Γ2 \/
(x, a) ∈ Γ2 /\ x `notin` domset Γ1 ->
(x, a) ∈ Γ1 \/ (x, a) ∈ Γ2
A, B: Type x: atom a: A Γ1, Γ2: list (atom * A) H: uniq Γ1 H0: uniq Γ2 H1: disjoint Γ1 Γ2
(x, a) ∈ Γ1 \/ (x, a) ∈ Γ2 ->
(x, a) ∈ Γ1 /\ x `notin` domset Γ2 \/
(x, a) ∈ Γ2 /\ x `notin` domset Γ1
A, B: Type x: atom a: A Γ1, Γ2: list (atom * A) H: uniq Γ1 H0: uniq Γ2 H1: disjoint Γ1 Γ2 inΓ1: (x, a) ∈ Γ1
(x, a) ∈ Γ1 /\ x `notin` domset Γ2 \/
(x, a) ∈ Γ2 /\ x `notin` domset Γ1
A, B: Type x: atom a: A Γ1, Γ2: list (atom * A) H: uniq Γ1 H0: uniq Γ2 H1: disjoint Γ1 Γ2 inΓ2: (x, a) ∈ Γ2
(x, a) ∈ Γ1 /\ x `notin` domset Γ2 \/
(x, a) ∈ Γ2 /\ x `notin` domset Γ1
A, B: Type x: atom a: A Γ1, Γ2: list (atom * A) H: uniq Γ1 H0: uniq Γ2 H1: disjoint Γ1 Γ2 inΓ1: (x, a) ∈ Γ1
(x, a) ∈ Γ1 /\ x `notin` domset Γ2 \/
(x, a) ∈ Γ2 /\ x `notin` domset Γ1
A, B: Type x: atom a: A Γ1, Γ2: list (atom * A) H: uniq Γ1 H0: uniq Γ2 H1: disjoint Γ1 Γ2 inΓ1: (x, a) ∈ Γ1
(x, a) ∈ Γ1 /\ x `notin` domset Γ2
A, B: Type x: atom a: A Γ1, Γ2: list (atom * A) H: uniq Γ1 H0: uniq Γ2 H1: disjoint Γ1 Γ2 inΓ1: (x, a) ∈ Γ1
(x, a) ∈ Γ1
A, B: Type x: atom a: A Γ1, Γ2: list (atom * A) H: uniq Γ1 H0: uniq Γ2 H1: disjoint Γ1 Γ2 inΓ1: (x, a) ∈ Γ1
x `notin` domset Γ2
A, B: Type x: atom a: A Γ1, Γ2: list (atom * A) H: uniq Γ1 H0: uniq Γ2 H1: disjoint Γ1 Γ2 inΓ1: (x, a) ∈ Γ1
(x, a) ∈ Γ1
auto.
A, B: Type x: atom a: A Γ1, Γ2: list (atom * A) H: uniq Γ1 H0: uniq Γ2 H1: disjoint Γ1 Γ2 inΓ1: (x, a) ∈ Γ1
x `notin` domset Γ2
eauto using disjoint_dom1 with tea_alist.
A, B: Type x: atom a: A Γ1, Γ2: list (atom * A) H: uniq Γ1 H0: uniq Γ2 H1: disjoint Γ1 Γ2 inΓ2: (x, a) ∈ Γ2
(x, a) ∈ Γ1 /\ x `notin` domset Γ2 \/
(x, a) ∈ Γ2 /\ x `notin` domset Γ1
A, B: Type x: atom a: A Γ1, Γ2: list (atom * A) H: uniq Γ1 H0: uniq Γ2 H1: disjoint Γ1 Γ2 inΓ2: (x, a) ∈ Γ2
(x, a) ∈ Γ2 /\ x `notin` domset Γ1
A, B: Type x: atom a: A Γ1, Γ2: list (atom * A) H: uniq Γ1 H0: uniq Γ2 H1: disjoint Γ1 Γ2 inΓ2: (x, a) ∈ Γ2
(x, a) ∈ Γ2
A, B: Type x: atom a: A Γ1, Γ2: list (atom * A) H: uniq Γ1 H0: uniq Γ2 H1: disjoint Γ1 Γ2 inΓ2: (x, a) ∈ Γ2
x `notin` domset Γ1
A, B: Type x: atom a: A Γ1, Γ2: list (atom * A) H: uniq Γ1 H0: uniq Γ2 H1: disjoint Γ1 Γ2 inΓ2: (x, a) ∈ Γ2
(x, a) ∈ Γ2
auto.
A, B: Type x: atom a: A Γ1, Γ2: list (atom * A) H: uniq Γ1 H0: uniq Γ2 H1: disjoint Γ1 Γ2 inΓ2: (x, a) ∈ Γ2
x `notin` domset Γ1
eauto using disjoint_dom1 with tea_alist.
A, B: Type x: atom a: A Γ1, Γ2: list (atom * A) H: uniq Γ1 H0: uniq Γ2 H1: disjoint Γ1 Γ2
(x, a) ∈ Γ1 /\ x `notin` domset Γ2 \/
(x, a) ∈ Γ2 /\ x `notin` domset Γ1 ->
(x, a) ∈ Γ1 \/ (x, a) ∈ Γ2
tauto.Qed.
A, B: Type
forall (xy : atom) (ab : A) (Γ : list (atom * A)),
uniq ((y, b) :: Γ) ->
(x, a) ∈ ((y, b) :: Γ) <->
x = y /\ a = b /\ x `notin` domset Γ \/
(x, a) ∈ Γ /\ x <> y
A, B: Type
forall (xy : atom) (ab : A) (Γ : list (atom * A)),
uniq ((y, b) :: Γ) ->
(x, a) ∈ ((y, b) :: Γ) <->
x = y /\ a = b /\ x `notin` domset Γ \/
(x, a) ∈ Γ /\ x <> y
A, B: Type x, y: atom a, b: A Γ: list (atom * A)
uniq ((y, b) :: Γ) ->
(x, a) ∈ ((y, b) :: Γ) <->
x = y /\ a = b /\ x `notin` domset Γ \/
(x, a) ∈ Γ /\ x <> y
A, B: Type x, y: atom a, b: A Γ: list (atom * A)
uniq (y ~ b ++ Γ) ->
(x, a) ∈ (y ~ b ++ Γ) <->
x = y /\ a = b /\ x `notin` domset Γ \/
(x, a) ∈ Γ /\ x <> y
A, B: Type x, y: atom a, b: A Γ: list (atom * A) H: uniq (y ~ b ++ Γ)
(x, a) ∈ (y ~ b ++ Γ) <->
x = y /\ a = b /\ x `notin` domset Γ \/
(x, a) ∈ Γ /\ x <> y
A, B: Type x, y: atom a, b: A Γ: list (atom * A) H: uniq (y ~ b ++ Γ)
(x, a) ∈ (y ~ b) /\ x `notin` domset Γ \/
(x, a) ∈ Γ /\ x `notin` domset (y ~ b) <->
x = y /\ a = b /\ x `notin` domset Γ \/
(x, a) ∈ Γ /\ x <> y
A, B: Type x, y: atom a, b: A Γ: list (atom * A) H: uniq (y ~ b ++ Γ)
(x = y /\ a = b) /\ x `notin` domset Γ \/
(x, a) ∈ Γ /\ x <> y <->
x = y /\ a = b /\ x `notin` domset Γ \/
(x, a) ∈ Γ /\ x <> y
tauto.Qed.Endin_theorems_uniq.(** * Facts about [binds] *)(* *********************************************************************** *)Sectionbinds_theorems.Context
(A : Type).Implicit Types
(xy : atom)
(ab : A)
(Γ : list (atom * A)).
A: Type
forallxaΓ,
(foralla0b, {a0 = b} + {a0 <> b}) ->
{(x, a) ∈ Γ} + {~ (x, a) ∈ Γ}
A: Type
forallxaΓ,
(foralla0b, {a0 = b} + {a0 <> b}) ->
{(x, a) ∈ Γ} + {~ (x, a) ∈ Γ}
A: Type
forallxaΓ,
(foralla0b, {a0 = b} + {a0 <> b}) ->
{(x, a) ∈ Γ} + {~ (x, a) ∈ Γ}
A: Type x: atom a: A Γ: list (atom * A) X: forallab, {a = b} + {a <> b}
{(x, a) ∈ Γ} + {~ (x, a) ∈ Γ}
A: Type x: atom a: A X: forallab, {a = b} + {a <> b}
{(x, a) ∈ []} + {~ (x, a) ∈ []}
A: Type x: atom a: A X: forallab, {a = b} + {a <> b} x0: atom a0: A xs: alist A IHΓ: {(x, a) ∈ xs} + {~ (x, a) ∈ xs}
{(x, a) ∈ (x0 ~ a0 ++ xs)} +
{~ (x, a) ∈ (x0 ~ a0 ++ xs)}
A: Type x: atom a: A X: forallab, {a = b} + {a <> b}
{(x, a) ∈ []} + {~ (x, a) ∈ []}
A: Type x: atom a: A X: forallab, {a = b} + {a <> b}
~ (x, a) ∈ []
auto.
A: Type x: atom a: A X: forallab, {a = b} + {a <> b} x0: atom a0: A xs: alist A IHΓ: {(x, a) ∈ xs} + {~ (x, a) ∈ xs}
{(x, a) ∈ (x0 ~ a0 ++ xs)} +
{~ (x, a) ∈ (x0 ~ a0 ++ xs)}
A: Type x: atom a: A X: forallab, {a = b} + {a <> b} x0: atom a0: A xs: alist A e: (x, a) ∈ xs
{(x, a) ∈ (x0 ~ a0 ++ xs)} +
{~ (x, a) ∈ (x0 ~ a0 ++ xs)}
A: Type x: atom a: A X: forallab, {a = b} + {a <> b} x0: atom a0: A xs: alist A n: ~ (x, a) ∈ xs
{(x, a) ∈ (x0 ~ a0 ++ xs)} +
{~ (x, a) ∈ (x0 ~ a0 ++ xs)}
A: Type x: atom a: A X: forallab, {a = b} + {a <> b} x0: atom a0: A xs: alist A e: (x, a) ∈ xs
{(x, a) ∈ (x0 ~ a0 ++ xs)} +
{~ (x, a) ∈ (x0 ~ a0 ++ xs)}
A: Type x: atom a: A X: forallab, {a = b} + {a <> b} x0: atom a0: A xs: alist A e: (x, a) ∈ xs
(x, a) ∈ (x0 ~ a0 ++ xs)
A: Type x: atom a: A X: forallab, {a = b} + {a <> b} x0: atom a0: A xs: alist A e: (x, a) ∈ xs
(x, a) = (x0, a0) \/ (x, a) ∈ xs
nowright.
A: Type x: atom a: A X: forallab, {a = b} + {a <> b} x0: atom a0: A xs: alist A n: ~ (x, a) ∈ xs
{(x, a) ∈ (x0 ~ a0 ++ xs)} +
{~ (x, a) ∈ (x0 ~ a0 ++ xs)}
A: Type a: A X: forallab, {a = b} + {a <> b} x0: atom a0: A xs: alist A n: ~ (x0, a) ∈ xs DESTR_EQs: x0 = x0
{(x0, a) ∈ (x0 ~ a0 ++ xs)} +
{~ (x0, a) ∈ (x0 ~ a0 ++ xs)}
A: Type x: atom a: A X: forallab, {a = b} + {a <> b} x0: atom a0: A xs: alist A n: ~ (x, a) ∈ xs DESTR_NEQ: x <> x0 DESTR_NEQs: x0 <> x
{(x, a) ∈ (x0 ~ a0 ++ xs)} +
{~ (x, a) ∈ (x0 ~ a0 ++ xs)}
A: Type a: A X: forallab, {a = b} + {a <> b} x0: atom a0: A xs: alist A n: ~ (x0, a) ∈ xs DESTR_EQs: x0 = x0
{(x0, a) ∈ (x0 ~ a0 ++ xs)} +
{~ (x0, a) ∈ (x0 ~ a0 ++ xs)}
A: Type X: forallab, {a = b} + {a <> b} x0: atom a0: A xs: alist A n: ~ (x0, a0) ∈ xs DESTR_EQs: x0 = x0
A: Type X: forallab, {a = b} + {a <> b} x0: atom a0: A xs: alist A n: ~ (x0, a0) ∈ xs DESTR_EQs: x0 = x0
(x0, a0) ∈ (x0 ~ a0 ++ xs)
nowleft.
A: Type a: A X: forallab, {a = b} + {a <> b} x0: atom a0: A xs: alist A n: ~ (x0, a) ∈ xs DESTR_EQs: x0 = x0 n0: a <> a0
{(x0, a) ∈ (x0 ~ a0 ++ xs)} +
{~ (x0, a) ∈ (x0 ~ a0 ++ xs)}
A: Type a: A X: forallab, {a = b} + {a <> b} x0: atom a0: A xs: alist A n: ~ (x0, a) ∈ xs DESTR_EQs: x0 = x0 n0: a <> a0
~ (x0, a) ∈ (x0 ~ a0 ++ xs)
A: Type a: A X: forallab, {a = b} + {a <> b} x0: atom a0: A xs: alist A n: ~ (x0, a) ∈ xs DESTR_EQs: x0 = x0 n0: a <> a0
~ ((x0, a) = (x0, a0) \/ (x0, a) ∈ xs)
A: Type a: A X: forallab, {a = b} + {a <> b} x0: atom a0: A xs: alist A n: ~ (x0, a) ∈ xs DESTR_EQs: x0 = x0 n0: a <> a0 hyp: (x0, a) = (x0, a0)
False
A: Type a: A X: forallab, {a = b} + {a <> b} x0: atom a0: A xs: alist A n: ~ (x0, a) ∈ xs DESTR_EQs: x0 = x0 n0: a <> a0 hyp: (x0, a) ∈ xs
False
A: Type a: A X: forallab, {a = b} + {a <> b} x0: atom a0: A xs: alist A n: ~ (x0, a) ∈ xs DESTR_EQs: x0 = x0 n0: a <> a0 hyp: (x0, a) ∈ xs
False
contradiction.
A: Type x: atom a: A X: forallab, {a = b} + {a <> b} x0: atom a0: A xs: alist A n: ~ (x, a) ∈ xs DESTR_NEQ: x <> x0 DESTR_NEQs: x0 <> x
{(x, a) ∈ (x0 ~ a0 ++ xs)} +
{~ (x, a) ∈ (x0 ~ a0 ++ xs)}
A: Type x: atom a: A X: forallab, {a = b} + {a <> b} x0: atom a0: A xs: alist A n: ~ (x, a) ∈ xs DESTR_NEQ: x <> x0 DESTR_NEQs: x0 <> x
{(x, a) ∈ (x0 ~ a0 ++ xs)} +
{~ (x, a) ∈ (x0 ~ a0 ++ xs)}
A: Type x: atom a: A X: forallab, {a = b} + {a <> b} x0: atom a0: A xs: alist A n: ~ (x, a) ∈ xs DESTR_NEQ: x <> x0 DESTR_NEQs: x0 <> x
~ (x, a) ∈ (x0 ~ a0 ++ xs)
A: Type x: atom a: A X: forallab, {a = b} + {a <> b} x0: atom a0: A xs: alist A n: ~ (x, a) ∈ xs DESTR_NEQ: x <> x0 DESTR_NEQs: x0 <> x hyp: (x0, a0) = (x, a)
False
A: Type x: atom a: A X: forallab, {a = b} + {a <> b} x0: atom a0: A xs: alist A n: ~ (x, a) ∈ xs DESTR_NEQ: x <> x0 DESTR_NEQs: x0 <> x hyp: ToSubset_list (atom * A) ([] ++ xs) (x, a)
False
A: Type x: atom a: A X: forallab, {a = b} + {a <> b} x0: atom a0: A xs: alist A n: ~ (x, a) ∈ xs DESTR_NEQ: x <> x0 DESTR_NEQs: x0 <> x hyp: ToSubset_list (atom * A) ([] ++ xs) (x, a)
False
contradiction.}Defined.
A: Type
forallxΓ,
{a : A | (x, a) ∈ Γ} + (foralla, ~ (x, a) ∈ Γ)
A: Type
forallxΓ,
{a : A | (x, a) ∈ Γ} + (foralla, ~ (x, a) ∈ Γ)
A: Type
forallxΓ,
{a : A | (x, a) ∈ Γ} + (foralla, ~ (x, a) ∈ Γ)
A: Type x: atom Γ: list (atom * A)
{a : A | (x, a) ∈ Γ} + (foralla, ~ (x, a) ∈ Γ)
A: Type x: atom
{a : A | (x, a) ∈ []} + (foralla, ~ (x, a) ∈ [])
A: Type x: atom a: atom * A Γ: list (atom * A) IHΓ: {a : A | (x, a) ∈ Γ} + (foralla, ~ (x, a) ∈ Γ)
{a0 : A | (x, a0) ∈ (a :: Γ)} +
(foralla0, ~ (x, a0) ∈ (a :: Γ))
A: Type x: atom
{a : A | (x, a) ∈ []} + (foralla, ~ (x, a) ∈ [])
simpl_list; cbn; nowright.
A: Type x: atom a: atom * A Γ: list (atom * A) IHΓ: {a : A | (x, a) ∈ Γ} + (foralla, ~ (x, a) ∈ Γ)
{a0 : A | (x, a0) ∈ (a :: Γ)} +
(foralla0, ~ (x, a0) ∈ (a :: Γ))
A: Type x, y: atom a: A Γ: list (atom * A) IHΓ: {a : A | (x, a) ∈ Γ} + (foralla, ~ (x, a) ∈ Γ)
{a0 : A | (x, a0) ∈ ((y, a) :: Γ)} +
(foralla0, ~ (x, a0) ∈ ((y, a) :: Γ))
A: Type x, y: atom a: A Γ: list (atom * A) s: {a : A | (x, a) ∈ Γ}
{a0 : A | (x, a0) ∈ ((y, a) :: Γ)} +
(foralla0, ~ (x, a0) ∈ ((y, a) :: Γ))
A: Type x, y: atom a: A Γ: list (atom * A) n: foralla, ~ (x, a) ∈ Γ
{a0 : A | (x, a0) ∈ ((y, a) :: Γ)} +
(foralla0, ~ (x, a0) ∈ ((y, a) :: Γ))
A: Type x, y: atom a: A Γ: list (atom * A) s: {a : A | (x, a) ∈ Γ}
{a0 : A | (x, a0) ∈ ((y, a) :: Γ)} +
(foralla0, ~ (x, a0) ∈ ((y, a) :: Γ))
A: Type x, y: atom a: A Γ: list (atom * A) x0: A e: (x, x0) ∈ Γ
{a0 : A | (x, a0) ∈ ((y, a) :: Γ)} +
(foralla0, ~ (x, a0) ∈ ((y, a) :: Γ))
A: Type x, y: atom a: A Γ: list (atom * A) x0: A e: (x, x0) ∈ Γ
{a0 : A | (x, a0) ∈ ((y, a) :: Γ)}
A: Type x, y: atom a: A Γ: list (atom * A) x0: A e: (x, x0) ∈ Γ
(x, ?a) ∈ ((y, a) :: Γ)
A: Type x, y: atom a: A Γ: list (atom * A) x0: A e: (x, x0) ∈ Γ
ToSubset_list (atom * A) Γ (x, ?a)
eauto.
A: Type x, y: atom a: A Γ: list (atom * A) n: foralla, ~ (x, a) ∈ Γ
{a0 : A | (x, a0) ∈ ((y, a) :: Γ)} +
(foralla0, ~ (x, a0) ∈ ((y, a) :: Γ))
A: Type y: atom a: A Γ: list (atom * A) n: foralla, ~ (y, a) ∈ Γ DESTR_EQs: y = y
{a0 : A | (y, a0) ∈ ((y, a) :: Γ)} +
(foralla0, ~ (y, a0) ∈ ((y, a) :: Γ))
A: Type x, y: atom a: A Γ: list (atom * A) n: foralla, ~ (x, a) ∈ Γ DESTR_NEQ: x <> y DESTR_NEQs: y <> x
{a0 : A | (x, a0) ∈ ((y, a) :: Γ)} +
(foralla0, ~ (x, a0) ∈ ((y, a) :: Γ))
A: Type y: atom a: A Γ: list (atom * A) n: foralla, ~ (y, a) ∈ Γ DESTR_EQs: y = y
{a0 : A | (y, a0) ∈ ((y, a) :: Γ)} +
(foralla0, ~ (y, a0) ∈ ((y, a) :: Γ))
A: Type y: atom a: A Γ: list (atom * A) n: foralla, ~ (y, a) ∈ Γ DESTR_EQs: y = y
{a0 : A | (y, a0) ∈ ((y, a) :: Γ)}
A: Type y: atom a: A Γ: list (atom * A) n: foralla, ~ (y, a) ∈ Γ DESTR_EQs: y = y
(y, a) ∈ ((y, a) :: Γ)
nowleft.
A: Type x, y: atom a: A Γ: list (atom * A) n: foralla, ~ (x, a) ∈ Γ DESTR_NEQ: x <> y DESTR_NEQs: y <> x
{a0 : A | (x, a0) ∈ ((y, a) :: Γ)} +
(foralla0, ~ (x, a0) ∈ ((y, a) :: Γ))
A: Type x, y: atom a: A Γ: list (atom * A) n: foralla, ~ (x, a) ∈ Γ DESTR_NEQ: x <> y DESTR_NEQs: y <> x
{a0 : A | (x, a0) ∈ ((y, a) :: Γ)} +
(foralla0, ~ (x, a0) ∈ ((y, a) :: Γ))
A: Type x, y: atom a: A Γ: list (atom * A) n: foralla, ~ (x, a) ∈ Γ DESTR_NEQ: x <> y DESTR_NEQs: y <> x
foralla0, ~ (x, a0) ∈ ((y, a) :: Γ)
A: Type x, y: atom a: A Γ: list (atom * A) n: foralla, ~ (x, a) ∈ Γ DESTR_NEQ: x <> y DESTR_NEQs: y <> x a0: A
~ (x, a0) ∈ ((y, a) :: Γ)
A: Type x, y: atom a: A Γ: list (atom * A) n: foralla, ~ (x, a) ∈ Γ DESTR_NEQ: x <> y DESTR_NEQs: y <> x a0: A
~ ((x, a0) = (y, a) \/ (x, a0) ∈ Γ)
A: Type x, y: atom a: A Γ: list (atom * A) n: foralla, ~ (x, a) ∈ Γ DESTR_NEQ: x <> y DESTR_NEQs: y <> x a0: A contra: (x, a0) = (y, a)
False
A: Type x, y: atom a: A Γ: list (atom * A) n: foralla, ~ (x, a) ∈ Γ DESTR_NEQ: x <> y DESTR_NEQs: y <> x a0: A contra: (x, a0) ∈ Γ
False
A: Type x, y: atom a: A Γ: list (atom * A) n: foralla, ~ (x, a) ∈ Γ DESTR_NEQ: x <> y DESTR_NEQs: y <> x a0: A contra: (x, a0) = (y, a)
False
A: Type y: atom a: A Γ: list (atom * A) DESTR_NEQs, DESTR_NEQ: y <> y n: foralla, ~ (y, a) ∈ Γ contra: (y, a) = (y, a)
False
contradiction.
A: Type x, y: atom a: A Γ: list (atom * A) n: foralla, ~ (x, a) ∈ Γ DESTR_NEQ: x <> y DESTR_NEQs: y <> x a0: A contra: (x, a0) ∈ Γ
False
eapply n; eauto.}Defined.
A: Type
forallxΓ, decidable (existsa, (x, a) ∈ Γ)
A: Type
forallxΓ, decidable (existsa, (x, a) ∈ Γ)
A: Type x: atom Γ: list (atom * A)
decidable (existsa, (x, a) ∈ Γ)
A: Type x: atom Γ: list (atom * A)
(existsa, (x, a) ∈ Γ) \/ ~ (existsa, (x, a) ∈ Γ)
A: Type x: atom Γ: list (atom * A) n: foralla, (x, a) ∈ Γ -> False
(existsa, (x, a) ∈ Γ) \/
((existsa, (x, a) ∈ Γ) -> False)
A: Type x: atom Γ: list (atom * A) n: foralla, (x, a) ∈ Γ -> False
(existsa, (x, a) ∈ Γ) -> False
intros [? ?]...Defined.
A: Type
forallxaΓ1Γ2Γ3,
(x, a) ∈ (Γ1 ++ Γ3) -> (x, a) ∈ (Γ1 ++ Γ2 ++ Γ3)
A: Type
forallxaΓ1Γ2Γ3,
(x, a) ∈ (Γ1 ++ Γ3) -> (x, a) ∈ (Γ1 ++ Γ2 ++ Γ3)
A: Type
forallxaΓ1Γ2Γ3,
(x, a) ∈ (Γ1 ++ Γ3) -> (x, a) ∈ (Γ1 ++ Γ2 ++ Γ3)
A: Type x: atom a: A Γ1, Γ2, Γ3: list (atom * A) H: (x, a) ∈ (Γ1 ++ Γ3)
(x, a) ∈ (Γ1 ++ Γ2 ++ Γ3)
A: Type x: atom a: A Γ1, Γ2, Γ3: list (atom * A) H: (x, a) ∈ Γ1 \/ (x, a) ∈ Γ3
(x, a) ∈ Γ1 \/ (x, a) ∈ Γ2 \/ (x, a) ∈ Γ3
intuition.Qed.
A: Type
forallxabΓ1Γ2,
(x, a) ∈ (Γ1 ++ x ~ b ++ Γ2) ->
uniq (Γ1 ++ x ~ b ++ Γ2) -> a = b
A: Type
forallxabΓ1Γ2,
(x, a) ∈ (Γ1 ++ x ~ b ++ Γ2) ->
uniq (Γ1 ++ x ~ b ++ Γ2) -> a = b
A: Type x: atom a, b: A Γ1, Γ2: list (atom * A) J: (x, a) ∈ (Γ1 ++ x ~ b ++ Γ2) H: uniq (Γ1 ++ x ~ b ++ Γ2)
a = b
A: Type x: atom a, b: A Γ1, Γ2: list (atom * A) J: (x, a) ∈ (Γ1 ++ x ~ b ++ Γ2) H: uniq Γ1 /\
(True /\ uniq Γ2 /\ x `notin` domset Γ2) /\
x `notin` domset Γ1 /\ disjoint Γ2 Γ1
a = b
A: Type x: atom a, b: A Γ1, Γ2: list (atom * A) J: (x, a) ∈ Γ1 \/ (x, a) = (x, b) \/ (x, a) ∈ Γ2 H: uniq Γ1 /\
(True /\ uniq Γ2 /\ x `notin` domset Γ2) /\
x `notin` domset Γ1 /\ disjoint Γ2 Γ1
a = b
A: Type x: atom a, b: A Γ1, Γ2: list (atom * A) H0: (x, a) ∈ Γ1 H: uniq Γ1 /\
(True /\ uniq Γ2 /\ x `notin` domset Γ2) /\
x `notin` domset Γ1 /\ disjoint Γ2 Γ1
a = b
A: Type x: atom a, b: A Γ1, Γ2: list (atom * A) H0: (x, a) = (x, b) \/ (x, a) ∈ Γ2 H: uniq Γ1 /\
(True /\ uniq Γ2 /\ x `notin` domset Γ2) /\
x `notin` domset Γ1 /\ disjoint Γ2 Γ1
a = b
A: Type x: atom a, b: A Γ1, Γ2: list (atom * A) H0: (x, a) ∈ Γ1 H: uniq Γ1 /\
(True /\ uniq Γ2 /\ x `notin` domset Γ2) /\
x `notin` domset Γ1 /\ disjoint Γ2 Γ1
a = b
A: Type x: atom a, b: A Γ1, Γ2: list (atom * A) H0: (x, a) ∈ Γ1 H1: uniq Γ1 H2: True H: x `in` domset Γ1 -> False H5: disjoint Γ2 Γ1 H3: uniq Γ2 H6: x `in` domset Γ2 -> False
a = b
A: Type x: atom a, b: A Γ1, Γ2: list (atom * A) H0: (x, a) ∈ Γ1 H1: uniq Γ1 H2: True H: x `in` domset Γ1 -> False H5: disjoint Γ2 Γ1 H3: uniq Γ2 H6: x `in` domset Γ2 -> False
x `in` domset Γ1
A: Type x: atom a, b: A Γ1, Γ2: list (atom * A) H0: (x, a) ∈ Γ1 H1: uniq Γ1 H2: True H: x `in` domset Γ1 -> False H5: disjoint Γ2 Γ1 H3: uniq Γ2 H6: x `in` domset Γ2 -> False
existsa, (x, a) ∈ Γ1
eauto.
A: Type x: atom a, b: A Γ1, Γ2: list (atom * A) H0: (x, a) = (x, b) \/ (x, a) ∈ Γ2 H: uniq Γ1 /\
(True /\ uniq Γ2 /\ x `notin` domset Γ2) /\
x `notin` domset Γ1 /\ disjoint Γ2 Γ1
a = b
A: Type x: atom a, b: A Γ1, Γ2: list (atom * A) H0: (x, a) = (x, b) H: uniq Γ1 /\
(True /\ uniq Γ2 /\ x `notin` domset Γ2) /\
x `notin` domset Γ1 /\ disjoint Γ2 Γ1
a = b
A: Type x: atom a, b: A Γ1, Γ2: list (atom * A) H0: (x, a) ∈ Γ2 H: uniq Γ1 /\
(True /\ uniq Γ2 /\ x `notin` domset Γ2) /\
x `notin` domset Γ1 /\ disjoint Γ2 Γ1
a = b
A: Type x: atom a, b: A Γ1, Γ2: list (atom * A) H0: (x, a) = (x, b) H: uniq Γ1 /\
(True /\ uniq Γ2 /\ x `notin` domset Γ2) /\
x `notin` domset Γ1 /\ disjoint Γ2 Γ1
a = b
nowinversion H0.
A: Type x: atom a, b: A Γ1, Γ2: list (atom * A) H0: (x, a) ∈ Γ2 H: uniq Γ1 /\
(True /\ uniq Γ2 /\ x `notin` domset Γ2) /\
x `notin` domset Γ1 /\ disjoint Γ2 Γ1
a = b
A: Type x: atom a, b: A Γ1, Γ2: list (atom * A) H0: (x, a) ∈ Γ2 H1: uniq Γ1 H2: True H: x `in` domset Γ1 -> False H5: disjoint Γ2 Γ1 H3: uniq Γ2 H6: x `in` domset Γ2 -> False
a = b
A: Type x: atom a, b: A Γ1, Γ2: list (atom * A) H0: (x, a) ∈ Γ2 H1: uniq Γ1 H2: True H: x `in` domset Γ1 -> False H5: disjoint Γ2 Γ1 H3: uniq Γ2 H6: x `in` domset Γ2 -> False
x `in` domset Γ2
A: Type x: atom a, b: A Γ1, Γ2: list (atom * A) H0: (x, a) ∈ Γ2 H1: uniq Γ1 H2: True H: x `in` domset Γ1 -> False H5: disjoint Γ2 Γ1 H3: uniq Γ2 H6: x `in` domset Γ2 -> False
existsa, (x, a) ∈ Γ2
eauto.Qed.
A: Type
forallxyabΓ1Γ2,
(x, a) ∈ (Γ1 ++ y ~ b ++ Γ2) ->
x <> y -> (x, a) ∈ (Γ1 ++ Γ2)
A: Type
forallxyabΓ1Γ2,
(x, a) ∈ (Γ1 ++ y ~ b ++ Γ2) ->
x <> y -> (x, a) ∈ (Γ1 ++ Γ2)
A: Type x, y: atom a, b: A Γ1, Γ2: list (atom * A) J: (x, a) ∈ (Γ1 ++ y ~ b ++ Γ2)
x <> y -> (x, a) ∈ (Γ1 ++ Γ2)
A: Type x, y: atom a, b: A Γ1, Γ2: list (atom * A) J: (x, a) ∈ Γ1 \/ (x, a) = (y, b) \/ (x, a) ∈ Γ2
x <> y -> (x, a) ∈ Γ1 \/ (x, a) ∈ Γ2
A: Type x, y: atom a, b: A Γ1, Γ2: list (atom * A) J: (x, a) ∈ Γ1 \/ (x, a) = (y, b) \/ (x, a) ∈ Γ2 H: x <> y
(x, a) ∈ Γ1 \/ (x, a) ∈ Γ2
intuition (preprocess; easy).Qed.
A: Type
forallxabΓ,
(x, a) ∈ Γ -> (x, b) ∈ Γ -> uniq Γ -> a = b
A: Type
forallxabΓ,
(x, a) ∈ Γ -> (x, b) ∈ Γ -> uniq Γ -> a = b
A: Type x: atom a, b: A Γ: list (atom * A) hyp1: (x, a) ∈ Γ hyp2: (x, b) ∈ Γ Hu: uniq Γ
a = b
A: Type x: atom a, b: A hyp1: (x, a) ∈ [] hyp2: (x, b) ∈ [] Hu: uniq []
a = b
A: Type x: atom a, b: A x0: atom a0: A Γ': alist A hyp1: (x, a) ∈ (x0 ~ a0 ++ Γ') hyp2: (x, b) ∈ (x0 ~ a0 ++ Γ') Hu: uniq (x0 ~ a0 ++ Γ') IH: (x, a) ∈ Γ' -> (x, b) ∈ Γ' -> uniq Γ' -> a = b
a = b
A: Type x: atom a, b: A hyp1: (x, a) ∈ [] hyp2: (x, b) ∈ [] Hu: uniq []
a = b
inversion hyp1.
A: Type x: atom a, b: A x0: atom a0: A Γ': alist A hyp1: (x, a) ∈ (x0 ~ a0 ++ Γ') hyp2: (x, b) ∈ (x0 ~ a0 ++ Γ') Hu: uniq (x0 ~ a0 ++ Γ') IH: (x, a) ∈ Γ' -> (x, b) ∈ Γ' -> uniq Γ' -> a = b
a = b
A: Type x: atom a, b: A x0: atom a0: A Γ': alist A hyp1: (x, a) = (x0, a0) \/ (x, a) ∈ Γ' hyp2: (x, b) = (x0, a0) \/ (x, b) ∈ Γ' Hu: uniq (x0 ~ a0 ++ Γ') IH: (x, a) ∈ Γ' -> (x, b) ∈ Γ' -> uniq Γ' -> a = b
a = b
A: Type x: atom a, b: A x0: atom a0: A Γ': alist A hyp1: (x, a) = (x0, a0) hyp2: (x, b) = (x0, a0) Hu: uniq (x0 ~ a0 ++ Γ') IH: (x, a) ∈ Γ' -> (x, b) ∈ Γ' -> uniq Γ' -> a = b
a = b
A: Type x: atom a, b: A x0: atom a0: A Γ': alist A hyp1: (x, a) = (x0, a0) hyp2: (x, b) ∈ Γ' Hu: uniq (x0 ~ a0 ++ Γ') IH: (x, a) ∈ Γ' -> (x, b) ∈ Γ' -> uniq Γ' -> a = b
a = b
A: Type x: atom a, b: A x0: atom a0: A Γ': alist A hyp1: (x, a) ∈ Γ' hyp2: (x, b) = (x0, a0) Hu: uniq (x0 ~ a0 ++ Γ') IH: (x, a) ∈ Γ' -> (x, b) ∈ Γ' -> uniq Γ' -> a = b
a = b
A: Type x: atom a, b: A x0: atom a0: A Γ': alist A hyp1: (x, a) ∈ Γ' hyp2: (x, b) ∈ Γ' Hu: uniq (x0 ~ a0 ++ Γ') IH: (x, a) ∈ Γ' -> (x, b) ∈ Γ' -> uniq Γ' -> a = b
a = b
A: Type x: atom a, b: A x0: atom a0: A Γ': alist A hyp1: (x, a) = (x0, a0) hyp2: (x, b) = (x0, a0) Hu: uniq (x0 ~ a0 ++ Γ') IH: (x, a) ∈ Γ' -> (x, b) ∈ Γ' -> uniq Γ' -> a = b
a = b
A: Type b: A x0: atom a0: A Γ': alist A hyp2: (x0, b) = (x0, a0) Hu: uniq (x0 ~ a0 ++ Γ') IH: (x0, a0) ∈ Γ' ->
(x0, b) ∈ Γ' -> uniq Γ' -> a0 = b
a0 = b
now inverts hyp2.
A: Type x: atom a, b: A x0: atom a0: A Γ': alist A hyp1: (x, a) = (x0, a0) hyp2: (x, b) ∈ Γ' Hu: uniq (x0 ~ a0 ++ Γ') IH: (x, a) ∈ Γ' -> (x, b) ∈ Γ' -> uniq Γ' -> a = b
a = b
A: Type b: A x0: atom a0: A Γ': alist A hyp2: (x0, b) ∈ Γ' Hu: uniq (x0 ~ a0 ++ Γ') IH: (x0, a0) ∈ Γ' ->
(x0, b) ∈ Γ' -> uniq Γ' -> a0 = b
a0 = b
A: Type b: A x0: atom a0: A Γ': alist A hyp2: (x0, b) ∈ Γ' IH: (x0, a0) ∈ Γ' ->
(x0, b) ∈ Γ' -> uniq Γ' -> a0 = b H1: uniq Γ' H3: x0 `notin` domset Γ'
a0 = b
now (apply in_in_domset in hyp2).
A: Type x: atom a, b: A x0: atom a0: A Γ': alist A hyp1: (x, a) ∈ Γ' hyp2: (x, b) = (x0, a0) Hu: uniq (x0 ~ a0 ++ Γ') IH: (x, a) ∈ Γ' -> (x, b) ∈ Γ' -> uniq Γ' -> a = b
a = b
A: Type a: A x0: atom a0: A Γ': alist A hyp1: (x0, a) ∈ Γ' Hu: uniq (x0 ~ a0 ++ Γ') IH: (x0, a) ∈ Γ' ->
(x0, a0) ∈ Γ' -> uniq Γ' -> a = a0
a = a0
A: Type a: A x0: atom a0: A Γ': alist A hyp1: (x0, a) ∈ Γ' IH: (x0, a) ∈ Γ' ->
(x0, a0) ∈ Γ' -> uniq Γ' -> a = a0 H1: uniq Γ' H3: x0 `notin` domset Γ'
a = a0
now (apply in_in_domset in hyp1).
A: Type x: atom a, b: A x0: atom a0: A Γ': alist A hyp1: (x, a) ∈ Γ' hyp2: (x, b) ∈ Γ' Hu: uniq (x0 ~ a0 ++ Γ') IH: (x, a) ∈ Γ' -> (x, b) ∈ Γ' -> uniq Γ' -> a = b
a = b
A: Type x: atom a, b: A x0: atom a0: A Γ': alist A hyp1: (x, a) ∈ Γ' hyp2: (x, b) ∈ Γ' IH: (x, a) ∈ Γ' -> (x, b) ∈ Γ' -> uniq Γ' -> a = b H1: uniq Γ' H3: x0 `notin` domset Γ'
a = b
auto.Qed.
A: Type
forallxaΓ1Γ2,
uniq (Γ1 ++ Γ2) -> (x, a) ∈ Γ1 -> x `notin` domset Γ2
A: Type
forallxaΓ1Γ2,
uniq (Γ1 ++ Γ2) -> (x, a) ∈ Γ1 -> x `notin` domset Γ2
A: Type x: atom a: A Γ1, Γ2: list (atom * A) H: uniq (Γ1 ++ Γ2) H0: (x, a) ∈ Γ1
x `notin` domset Γ2
A: Type x: atom a: A Γ1, Γ2: list (atom * A) H: uniq Γ1 /\ uniq Γ2 /\ disjoint Γ1 Γ2 H0: (x, a) ∈ Γ1
x `notin` domset Γ2
A: Type x: atom a: A Γ1, Γ2: list (atom * A) H: uniq Γ1 H1: uniq Γ2 H2: disjoint Γ1 Γ2 H0: (x, a) ∈ Γ1
x `notin` domset Γ2
A: Type x: atom a: A Γ1, Γ2: list (atom * A) H: uniq Γ1 H1: uniq Γ2 H2: disjoint Γ1 Γ2 H0: x `in` domset Γ1
x `notin` domset Γ2
eauto with tea_alist.Qed.
A: Type
forallxaΓ1Γ2,
uniq (Γ1 ++ Γ2) -> (x, a) ∈ Γ2 -> x `notin` domset Γ1
A: Type
forallxaΓ1Γ2,
uniq (Γ1 ++ Γ2) -> (x, a) ∈ Γ2 -> x `notin` domset Γ1
A: Type x: atom a: A Γ1, Γ2: list (atom * A) H: uniq (Γ1 ++ Γ2) H0: (x, a) ∈ Γ2
x `notin` domset Γ1
A: Type x: atom a: A Γ1, Γ2: list (atom * A) H: uniq Γ1 /\ uniq Γ2 /\ disjoint Γ1 Γ2 H0: (x, a) ∈ Γ2
x `notin` domset Γ1
A: Type x: atom a: A Γ1, Γ2: list (atom * A) H: uniq Γ1 H1: uniq Γ2 H2: disjoint Γ1 Γ2 H0: (x, a) ∈ Γ2
x `notin` domset Γ1
A: Type x: atom a: A Γ1, Γ2: list (atom * A) H: uniq Γ1 H1: uniq Γ2 H2: disjoint Γ1 Γ2 H0: x `in` domset Γ2
x `notin` domset Γ1
A: Type x: atom a: A Γ1, Γ2: list (atom * A) H: uniq Γ1 H1: uniq Γ2 H2: disjoint Γ2 Γ1 H0: x `in` domset Γ2
x `notin` domset Γ1
eauto with tea_alist.Qed.(* If x is in an alist, it is either in the front half or the back half. *)
A: Type
forallxaΓ,
(x, a) ∈ Γ -> existsΓ1Γ2, Γ = Γ1 ++ x ~ a ++ Γ2
A: Type
forallxaΓ,
(x, a) ∈ Γ -> existsΓ1Γ2, Γ = Γ1 ++ x ~ a ++ Γ2
A: Type x: atom a: A Γ: list (atom * A) Hin: (x, a) ∈ Γ
existsΓ1Γ2, Γ = Γ1 ++ x ~ a ++ Γ2
A: Type x: atom a: A Hin: (x, a) ∈ []
existsΓ1Γ2, [] = Γ1 ++ x ~ a ++ Γ2
A: Type x: atom a: A a0: atom * A Γ: list (atom * A) Hin: (x, a) ∈ (a0 :: Γ) IHΓ: (x, a) ∈ Γ -> existsΓ1Γ2, Γ = Γ1 ++ x ~ a ++ Γ2
existsΓ1Γ2, a0 :: Γ = Γ1 ++ x ~ a ++ Γ2
A: Type x: atom a: A Hin: (x, a) ∈ []
existsΓ1Γ2, [] = Γ1 ++ x ~ a ++ Γ2
now simpl_list in *.
A: Type x: atom a: A a0: atom * A Γ: list (atom * A) Hin: (x, a) ∈ (a0 :: Γ) IHΓ: (x, a) ∈ Γ -> existsΓ1Γ2, Γ = Γ1 ++ x ~ a ++ Γ2
existsΓ1Γ2, a0 :: Γ = Γ1 ++ x ~ a ++ Γ2
A: Type x: atom a: A z: atom a': A Γ: list (atom * A) Hin: (x, a) ∈ ((z, a') :: Γ) IHΓ: (x, a) ∈ Γ -> existsΓ1Γ2, Γ = Γ1 ++ x ~ a ++ Γ2
existsΓ1Γ2, (z, a') :: Γ = Γ1 ++ x ~ a ++ Γ2
A: Type x: atom a: A z: atom a': A Γ: list (atom * A) Hin: (x, a) = (z, a') \/ (x, a) ∈ Γ IHΓ: (x, a) ∈ Γ -> existsΓ1Γ2, Γ = Γ1 ++ x ~ a ++ Γ2
existsΓ1Γ2, (z, a') :: Γ = Γ1 ++ x ~ a ++ Γ2
A: Type x: atom a: A z: atom a': A Γ: list (atom * A) Hin: (x, a) = (z, a') IHΓ: (x, a) ∈ Γ -> existsΓ1Γ2, Γ = Γ1 ++ x ~ a ++ Γ2
existsΓ1Γ2, (z, a') :: Γ = Γ1 ++ x ~ a ++ Γ2
A: Type x: atom a: A z: atom a': A Γ: list (atom * A) Hin: (x, a) ∈ Γ IHΓ: (x, a) ∈ Γ -> existsΓ1Γ2, Γ = Γ1 ++ x ~ a ++ Γ2
existsΓ1Γ2, (z, a') :: Γ = Γ1 ++ x ~ a ++ Γ2
A: Type x: atom a: A z: atom a': A Γ: list (atom * A) Hin: (x, a) = (z, a') IHΓ: (x, a) ∈ Γ -> existsΓ1Γ2, Γ = Γ1 ++ x ~ a ++ Γ2
existsΓ1Γ2, (z, a') :: Γ = Γ1 ++ x ~ a ++ Γ2
A: Type z: atom a': A Γ: list (atom * A) IHΓ: (z, a') ∈ Γ -> existsΓ1Γ2, Γ = Γ1 ++ z ~ a' ++ Γ2
existsΓ1Γ2, (z, a') :: Γ = Γ1 ++ z ~ a' ++ Γ2
A: Type z: atom a': A Γ: list (atom * A) IHΓ: (z, a') ∈ Γ -> existsΓ1Γ2, Γ = Γ1 ++ z ~ a' ++ Γ2
(z, a') :: Γ = [] ++ z ~ a' ++ Γ
reflexivity.
A: Type x: atom a: A z: atom a': A Γ: list (atom * A) Hin: (x, a) ∈ Γ IHΓ: (x, a) ∈ Γ -> existsΓ1Γ2, Γ = Γ1 ++ x ~ a ++ Γ2
existsΓ1Γ2, (z, a') :: Γ = Γ1 ++ x ~ a ++ Γ2
A: Type x: atom a: A z: atom a': A Γ: list (atom * A) Hin: (x, a) ∈ Γ IHΓ: existsΓ1Γ2, Γ = Γ1 ++ x ~ a ++ Γ2
existsΓ1Γ2, (z, a') :: Γ = Γ1 ++ x ~ a ++ Γ2
A: Type x: atom a: A z: atom a': A Γ: list (atom * A) Hin: (x, a) ∈ Γ Γ1, Γ2: list (atom * A) rest: Γ = Γ1 ++ x ~ a ++ Γ2
existsΓ1Γ2, (z, a') :: Γ = Γ1 ++ x ~ a ++ Γ2
A: Type x: atom a: A z: atom a': A Γ1, Γ2: list (atom * A) Hin: (x, a) ∈ (Γ1 ++ x ~ a ++ Γ2)
existsΓ3Γ4,
(z, a') :: Γ1 ++ x ~ a ++ Γ2 = Γ3 ++ x ~ a ++ Γ4
A: Type x: atom a: A z: atom a': A Γ1, Γ2: list (atom * A) Hin: (x, a) ∈ (Γ1 ++ x ~ a ++ Γ2)
(z, a') :: Γ1 ++ x ~ a ++ Γ2 =
((z, a') :: Γ1) ++ x ~ a ++ Γ2
A: Type x: atom * A l, l': list (atom * A) J: Permutation l l' IHJ: uniq l <-> uniq l'
uniq (x :: l) <-> uniq (x :: l')
A: Type x, y: atom * A l: list (atom * A)
uniq (y :: x :: l) <-> uniq (x :: y :: l)
A: Type l, l', l'': list (atom * A) J1: Permutation l l' J2: Permutation l' l'' IHJ1: uniq l <-> uniq l' IHJ2: uniq l' <-> uniq l''
uniq l <-> uniq l''
A: Type
uniq [] <-> uniq []
reflexivity.
A: Type x: atom * A l, l': list (atom * A) J: Permutation l l' IHJ: uniq l <-> uniq l'
uniq (x :: l) <-> uniq (x :: l')
A: Type n: atom a: A l, l': list (atom * A) J: Permutation l l' IHJ: uniq l <-> uniq l'
uniq ((n, a) :: l) <-> uniq ((n, a) :: l')
A: Type n: atom a: A l, l': list (atom * A) J: Permutation l l' IHJ: uniq l <-> uniq l'
n `notin` domset l /\ uniq l <->
n `notin` domset l' /\ uniq l'
A: Type n: atom a: A l, l': list (atom * A) J: Permutation l l' IHJ: uniq l <-> uniq l'
n `notin` domset l' /\ uniq l' <->
n `notin` domset l' /\ uniq l'
tauto.
A: Type x, y: atom * A l: list (atom * A)
uniq (y :: x :: l) <-> uniq (x :: y :: l)
A: Type n: atom a: A n0: atom a0: A l: list (atom * A)
uniq ((n0, a0) :: (n, a) :: l) <->
uniq ((n, a) :: (n0, a0) :: l)
A: Type n: atom a: A n0: atom a0: A l: list (atom * A)
(n0 <> n /\ n0 `notin` domset l) /\
n `notin` domset l /\ uniq l <->
(n <> n0 /\ n `notin` domset l) /\
n0 `notin` domset l /\ uniq l
intuition.
A: Type l, l', l'': list (atom * A) J1: Permutation l l' J2: Permutation l' l'' IHJ1: uniq l <-> uniq l' IHJ2: uniq l' <-> uniq l''
uniq l <-> uniq l''
tauto.Qed.
forall (A : Type) (l1l2 : list (atom * A)) (x : atom)
(a : A),
Permutation l1 l2 -> (x, a) ∈ l1 <-> (x, a) ∈ l2
forall (A : Type) (l1l2 : list (atom * A)) (x : atom)
(a : A),
Permutation l1 l2 -> (x, a) ∈ l1 <-> (x, a) ∈ l2
A: Type l1, l2: list (atom * A) x: atom a: A H: Permutation l1 l2
(x, a) ∈ l1 <-> (x, a) ∈ l2
nowerewrite List.permutation_spec; eauto.Qed.Create HintDb tea_rw_perm.#[export] Hint Rewrite @perm_dom @perm_range @perm_domset @perm_disjoint_l @perm_disjoint_r
@uniq_perm using (auto; trysymmetry; auto) : tea_rw_perm.(** For any given finite set of atoms, we can generate an atom fresh for it. *)
forallL : AtomSet.t, {x : atom | x `notin` L}
forallL : AtomSet.t, {x : atom | x `notin` L}
L: AtomSet.t
{x : atom | x `notin` L}
L: AtomSet.t
fresh ((elements) L) `notin` L
L: AtomSet.t
~ fresh ((elements) L) ∈ (elements) L
apply (Name.fresh_not_in (AtomSet.elements L)).Qed.(** * Tactic support for picking fresh atoms *)(* ********************************************************************** *)Ltacltac_remove_dups xs :=
let recremovexsacc :=
match xs with
| List.nil => acc
| List.cons ?x?xs =>
match acc with
| context [x] => remove xs acc
| _ => remove xs (List.cons x acc)
endendinmatchtype of xs with
| List.list ?A =>
letxs := evalsimplin xs inletxs := remove xs (@List.nil A) inevalsimplin (List.rev xs)
end.(** The auxiliary tactic [simplify_list_of_atom_sets] takes a list of finite sets of atoms and unions everything together, returning the resulting single finite set. *)Ltacsimplify_list_of_atom_sets L :=
letL := evalsimplin L inletL := ltac_remove_dups L inletL := evalsimplin (List.fold_right AtomSet.union AtomSet.empty L) inmatch L with
| context C [AtomSet.union ?E AtomSet.empty] => context C [ E ]
end.(** [gather_atoms_with F] returns the union of all the finite sets [F x] where [x] is a variable from the context such that [F x] type checks. *)Ltacgather_atoms_with F :=
letapply_argx :=
matchtype of F with
| _ -> _ -> _ -> _ => constr:(@F _ _ x)
| _ -> _ -> _ => constr:(@F _ x)
| _ -> _ => constr:(@F x)
endinlet recgatherV :=
match goal with
| H : _ |- _ =>
letFH := apply_arg H inmatch V with
| context [FH] => fail1
| _ => gather (AtomSet.union FH V)
end
| _ => V
endinletL := gather AtomSet.empty inevalsimplin L.(** [beautify_fset V] assumes that [V] is built as a union of finite sets and returns the same set cleaned up: empty sets are removed and items are laid out in a nicely parenthesized way. *)Ltacbeautify_fset V :=
let recgoAccE :=
match E with
| AtomSet.union ?E1?E2 => letAcc2 := go Acc E2 in go Acc2 E1
| AtomSet.empty => Acc
| ?E1 => match Acc with
| AtomSet.empty => E1
| _ => constr:(AtomSet.union E1 Acc)
endendin go AtomSet.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. The variant [pick fresh Y] is similar, except that [Y] is fresh for "all atoms in the context." This version depends on the tactic [gather_atoms], which is responsible for returning the set of "all atoms in the context." By default, it returns the empty set, but users are free (and expected) to redefine it. *)Ltacgather_atoms :=
constr:(AtomSet.empty).Tactic Notation"pick""fresh"ident(Y) "for"constr(L) :=
letFr := fresh"Hfresh"inletL := beautify_fset L in
(destruct (atom_fresh L) as [Y Fr]).Tactic Notation"pick""fresh"ident(Y) :=
letL := gather_atoms in
pick fresh Y for L.Ltacpick_fresh y :=
pick fresh y.(** Example: We can redefine [gather_atoms] to return all the "obvious" atoms in the context using the [gather_atoms_with] thus giving us a "useful" version of the "[pick fresh]" tactic. *)Ltacgather_atoms ::=
letA := gather_atoms_with (funx : AtomSet.t => x) inletB := gather_atoms_with (funx : atom => AtomSet.singleton x) inconstr:(AtomSet.union A B).
atom ->
atom ->
atom -> AtomSet.t -> AtomSet.t -> AtomSet.t -> True
(* begin show *)
atom ->
atom ->
atom -> AtomSet.t -> AtomSet.t -> AtomSet.t -> True
x, y, z: atom L1, L2, L3: AtomSet.t
True
x, y, z: atom L1, L2, L3: AtomSet.t k: atom Hfresh: k
`notin` (L1
∪ (L2
∪ (L3 ∪ ({{x}} ∪ ({{y}} ∪ {{z}})))))
True
(** At this point in the proof, we have a new atom [k] and a hypothesis [Fr] that [k] is fresh for [x], [y], [z], [L1], [L2], and [L3]. *)trivial.Qed.Tactic Notation"pick""fresh"ident(atom_name)
"excluding"constr(L)
"and""apply"constr(H)
:=
first [apply (@H L) | eapply (@H L)];
match goal with
| |- forall_, ~ AtomSet.In _ _ -> _ =>
letFr := fresh"Fr"inintros atom_name Fr
| |- forall_, ~ AtomSet.In _ _ -> _ =>
fail1"because" atom_name "is already defined"
| _ =>
idtacend.Tactic Notation"pick""fresh"ident(atom_name)
"and""apply"constr(H)
:=
letL := gather_atoms inletL := beautify_fset L in
pick fresh atom_name excluding L andapply H.Ltacspecialize_cof H e :=
specialize (H e ltac:(fsetdec)).Ltacspecialize_freshly H :=
lete := fresh"e"in
pick fresh e;
specialize_cof H e.(** When the goal is a cofinite quantification, introduce a new atom and specialize assumption H to this variable. *)Ltacintros_cof H :=
match goal with
| |- foralle, ~ AtomSet.In e _ -> _ =>
matchtype of H with
| foralle, ~ AtomSet.In _ _ -> _ =>
lete := fresh"e"inletNotin := fresh"Notin"inintros e Notin; specialize_cof H e
| _ => fail"Argument should be cofinitely quantified hypothesis"endend.Ltacapply_cof H :=
intros_cof H; apply H.Ltaceapply_cof H :=
intros_cof H; eapply H.Ltaccleanup_cofinite :=
repeatmatch goal with
| H : foralle, ?x |- _ => specialize_freshly H
end.Ltaccc := cleanup_cofinite.