Module Freevar
Require Import List.
Require Import Arith.
Require Import Psatz.
Require Import Misc.
Require Import Setoid.
Require Import Morphisms.
Definition freevar :=
nat.
Lemma freevar_eq_dec :
forall (
v1 v2 :
freevar), {
v1 =
v2 } + {
v1 <>
v2 }.
Proof.
apply Nat.eq_dec.
Qed.
Lemma freevar_eq_dec_eq :
forall v1 v2 (
P :
v1 =
v2),
freevar_eq_dec v1 v2 =
left P.
Proof.
intros v1 v2 H. subst. destruct freevar_eq_dec; [|exfalso; tauto].
f_equal. erewrite UIP_nat. reflexivity.
Qed.
Lemma freevar_eq_dec_eq_ifte :
forall (
A :
Type) (
ifso ifelse :
A)
v1 v2,
v1 =
v2 -> (
if freevar_eq_dec v1 v2 then ifso else ifelse) =
ifso.
Proof.
intros. destruct freevar_eq_dec; tauto.
Qed.
Lemma freevar_eq_dec_neq_ifte :
forall (
A :
Type) (
ifso ifelse :
A)
v1 v2,
v1 <>
v2 -> (
if freevar_eq_dec v1 v2 then ifso else ifelse) =
ifelse.
Proof.
intros. destruct freevar_eq_dec; tauto.
Qed.
Lemma fresh :
forall (
L :
list freevar), {
x |
x \
notin L }.
Proof.
intros L.
assert (H : { x | forall y, y \in L -> y < x }).
- induction L.
+ exists 0. intros y [].
+ destruct IHL as [x IH].
exists (Nat.max (S a) x); unfold freevar in *.
intros y [Hy | Hy]; [|specialize (IH y Hy)]; lia.
- destruct H as [x Hx]; exists x.
intros H; apply Hx in H; lia.
Qed.
Global Opaque freevar.
Notation "'
forall'
x '∉'
L ,
P" := (
forall (
x :
freevar), ~
In x L ->
P) (
at level 200,
x ident,
only printing).
Tactic Notation "
pick"
ident(
x) "\
notin"
uconstr(
L) "
as"
ident(
H) :=
refine (
match (
fresh L)
with exist _ x H =>
_ end).
Tactic Notation "
pick"
ident(
x) "\
notin"
uconstr(
L) := (
let H :=
fresh "
H"
in pick x \
notin L as H).
Tactic Notation "
pick"
ident(
x) "∉"
uconstr(
L) "
as"
ident(
H) := (
pick x \
notin L as H).
Tactic Notation "
pick"
ident(
x) "∉"
uconstr(
L) := (
let H :=
fresh "
H"
in pick x \
notin L as H).
Definition list_remove x L :=
filter (
fun y =>
if freevar_eq_dec x y then false else true)
L.
Lemma list_remove_correct :
forall x y L,
y \
in list_remove x L <->
y \
in L /\
x <>
y.
Proof.
intros x y L.
unfold list_remove. rewrite filter_In.
destruct freevar_eq_dec; intuition congruence.
Qed.
Lemma list_remove_app :
forall x L1 L2,
list_remove x (
L1 ++
L2) =
list_remove x L1 ++
list_remove x L2.
Proof.
intros. unfold list_remove. induction L1.
- reflexivity.
- simpl. destruct freevar_eq_dec; simpl; rewrite IHL1; reflexivity.
Qed.
Definition list_diff (
L1 L2 :
list freevar) :=
filter (
fun x =>
if in_dec freevar_eq_dec x L2 then false else true)
L1.
Lemma list_diff_In_iff :
forall L1 L2 x,
x \
in list_diff L1 L2 <->
x \
in L1 /\
x \
notin L2.
Proof.
intros L1 L2 x. unfold list_diff.
rewrite filter_In.
destruct in_dec; intuition congruence.
Qed.
Global Instance list_diff_inc_Proper :
Proper (
list_inc ++>
list_inc -->
list_inc)
list_diff.
Proof.
intros L1 L2 H12 L3 L4 H34 x.
rewrite !list_diff_In_iff.
rewrite H12. rewrite H34.
tauto.
Qed.
Global Instance list_diff_same_Proper :
Proper (
list_same ==>
list_same ==>
list_same)
list_diff.
Proof.
intros L1 L2 H12 L3 L4 H34.
rewrite list_same_inc_iff in *.
split; apply list_diff_inc_Proper; tauto.
Qed.
Definition list_inter L1 L2 :=
filter (
fun y =>
if in_dec freevar_eq_dec y L1 then true else false)
L2.
Lemma list_inter_correct :
forall L1 L2 x,
x \
in list_inter L1 L2 <->
x \
in L1 /\
x \
in L2.
Proof.
intros L1 L2 x. unfold list_inter. rewrite filter_In.
destruct in_dec; try tauto. assert (~ (false = true)) by discriminate; tauto.
Qed.
Lemma list_inter_subl1 :
forall L1 L2,
list_inter L1 L2 \
subseteq L1.
Proof.
intros L1 L2 x; rewrite list_inter_correct; tauto.
Qed.
Lemma list_inter_subl2 :
forall L1 L2,
list_inter L1 L2 \
subseteq L2.
Proof.
intros L1 L2 x; rewrite list_inter_correct; tauto.
Qed.
Lemma list_inter_subr :
forall L1 L2 L3,
L1 \
subseteq list_inter L2 L3 <->
L1 \
subseteq L2 /\
L1 \
subseteq L3.
Proof.
intros L1 L2 L3; split.
- intros H; split; intros x; specialize (H x); rewrite list_inter_correct in H; tauto.
- intros [H1 H2] x; specialize (H1 x); specialize (H2 x); rewrite list_inter_correct; tauto.
Qed.
Inductive distinct :
list freevar ->
nat ->
list freevar ->
Prop :=
|
distinct_nil :
forall L,
distinct L 0
nil
|
distinct_cons :
forall L1 L2 x n,
x \
notin L1 ->
distinct (
x ::
L1)
n L2 ->
distinct L1 (
S n) (
x ::
L2).
Fixpoint fresh_list L n :=
match n with
|
O =>
nil
|
S n =>
let x :=
proj1_sig (
fresh L)
in x ::
fresh_list (
x ::
L)
n
end.
Lemma fresh_list_distinct :
forall n L,
distinct L n (
fresh_list L n).
Proof.
induction n as [|n]; intros L; simpl.
- constructor.
- constructor.
+ destruct fresh. simpl. assumption.
+ apply IHn.
Qed.
Lemma distinct_distinct :
forall n x L1 L2,
distinct L1 n L2 ->
x \
in L1 ->
x \
in L2 ->
False.
Proof.
intros n x L1 L2 H. induction H.
- simpl. tauto.
- simpl in *. intros H1 [-> | H2]; tauto.
Qed.
Lemma distinct_incl :
forall n L1 L2 L,
L2 \
subseteq L1 ->
distinct L1 n L ->
distinct L2 n L.
Proof.
intros n L1 L2 L Hinc H. revert L2 Hinc. induction H; intros L3 Hinc.
- constructor.
- constructor.
+ rewrite Hinc. assumption.
+ apply IHdistinct. rewrite Hinc. prove_list_inc.
Qed.
Lemma distinct_length :
forall n L1 L2,
distinct L1 n L2 ->
length L2 =
n.
Proof.
intros n L1 L2 H. induction H.
- reflexivity.
- simpl. f_equal. assumption.
Qed.
Lemma notin_app_iff :
forall (
x :
freevar)
L1 L2,
x \
notin L1 ++
L2 <->
x \
notin L1 /\
x \
notin L2.
Proof.
intros. rewrite in_app_iff. tauto.
Qed.
Lemma notin_app_l :
forall (
x :
freevar)
L1 L2,
x \
notin L1 ++
L2 ->
x \
notin L1.
Proof.
intros. rewrite notin_app_iff in *. tauto.
Qed.
Lemma notin_app_r :
forall (
x :
freevar)
L1 L2,
x \
notin L1 ++
L2 ->
x \
notin L2.
Proof.
intros. rewrite notin_app_iff in *. tauto.
Qed.
Lemma notin_cons1 :
forall (
x y :
freevar)
L,
x \
notin y ::
L ->
x <>
y.
Proof.
intros ? ? ? ? ->. simpl in *. tauto.
Qed.
Lemma notin_cons2 :
forall (
x y :
freevar)
L,
x \
notin y ::
L ->
y <>
x.
Proof.
intros ? ? ? ? ->. simpl in *. tauto.
Qed.
Lemma notin_one :
forall (
x y :
freevar),
y <>
x ->
x \
notin (
y ::
nil).
Proof.
intros. simpl. tauto.
Qed.
Lemma qed_opaque_helper {
A :
Type} (
x :
A) : {
y |
y =
x }.
Proof.
exists x. reflexivity.
Qed.
Definition qed_opaque {
A :
Type} (
x :
A) :
A :=
proj1_sig (
qed_opaque_helper x).
Definition qed_opaque_eq (
A :
Type) (
x :
A) :
qed_opaque x =
x :=
proj2_sig (
qed_opaque_helper x).
Global Opaque qed_opaque qed_opaque_eq.
Definition Bound (
L :
list freevar) :
list freevar :=
qed_opaque L.
Definition Bound_eq (
L :
list freevar) :
Bound L =
L :=
qed_opaque_eq _ L.
Global Opaque Bound.
Ltac bound := (
let L :=
fresh "
L"
in evar (
L :
list freevar);
let r :=
constr:(
Bound L)
in subst L;
exact r).
Ltac use_fresh_aux x L HxL :=
let L := (
eval hnf in L)
in
lazymatch L with
| ?
L1 ++ ?
L2 =>
use_fresh_aux x L2 (
notin_app_r x L1 L2 HxL)
| ?
y :: ?
L2 =>
use_fresh_aux x L2 (
notin_app_r x (
y ::
nil)
L2 HxL)
|
_ =>
match goal with
| [ |-
x \
notin ?
L2 ] =>
refine (
notin_app_l _ L2 _ HxL)
| [ |-
x \
in ?
L2 ->
False ] =>
refine (
notin_app_l _ L2 _ HxL)
| [ |-
x <> ?
y ] =>
refine (
notin_cons1 _ y _ HxL)
| [ |- ?
y <>
x ] =>
refine (
notin_cons2 _ y _ HxL)
| [ |- ?
y \
notin (
x ::
nil) ] =>
refine (
notin_one _ _ (
notin_cons1 _ y _ HxL))
| [
H :
x \
in ?
L2 |-
_ ] =>
exfalso;
refine (
notin_app_l _ L2 _ HxL H)
| [
H :
x = ?
y |-
_ ] =>
exfalso;
refine (
notin_cons1 _ y _ HxL H)
| [
H : ?
y =
x |-
_ ] =>
exfalso;
refine (
notin_cons2 _ y _ HxL H)
| [
H : ?
y \
in (
x ::
nil) |-
_ ] =>
exfalso;
refine (
notin_one _ _ (
notin_cons1 _ y _ HxL)
H)
end
end.
Ltac use_fresh x :=
lazymatch goal with
| [
H :
x \
notin Bound ?
L |-
_ ] =>
use_fresh_aux x L (@
eq_ind _ _ (
fun L2 =>
x \
notin L2)
H _ (
Bound_eq L));
lazymatch goal with
| [ |-
list freevar ] =>
shelve
end
| [
H :
x \
in Bound ?
L ->
False |-
_ ] =>
use_fresh_aux x L (@
eq_ind _ _ (
fun L2 =>
x \
notin L2)
H _ (
Bound_eq L));
lazymatch goal with
| [ |-
list freevar ] =>
shelve
end
end.
Ltac specialize_fresh H x :=
match type of H with
|
forall y,
y \
notin ?
L ->
_ =>
let H2 :=
fresh in
assert (
H2 :
x \
notin L)
by use_fresh x;
specialize (
H x H2);
clear H2
end.
Tactic Notation "
pick" "
fresh"
ident(
x) "
as"
ident(
H) :=
pick x \
notin (
Bound _)
as H.
Tactic Notation "
pick" "
fresh"
ident(
x) :=
pick x \
notin (
Bound _).
Tactic Notation "
pickn"
constr(
n) "
distinct"
ident(
xs) "\
notin"
uconstr(
L) "
as"
ident(
H) :=
refine ((
fun xs (
H :
distinct L n xs) =>
_) (
fresh_list L n) (
fresh_list_distinct n L)).
Tactic Notation "
pickn"
constr(
n) "
distinct"
ident(
xs) "\
notin"
uconstr(
L) :=
(
let H :=
fresh "
H"
in pickn n distinct xs \
notin L as H).
Tactic Notation "
pickn"
constr(
n) "
distinct"
ident(
xs) "∉"
uconstr(
L) "
as"
ident(
H) :=
(
pickn n distinct xs \
notin L as H).
Tactic Notation "
pickn"
constr(
n) "
distinct"
ident(
xs) "∉"
uconstr(
L) :=
(
pickn n distinct xs \
notin L).
Tactic Notation "
pickn"
constr(
n) "
distinct" "
fresh"
ident(
xs) "
as"
ident(
H) :=
pickn n distinct xs \
notin (
Bound _)
as H.
Tactic Notation "
pickn"
constr(
n) "
distinct" "
fresh"
ident(
x) :=
pickn n distinct xs \
notin (
Bound _).