From Coq Require Import List Sorting.Permutation.
Import List.ListNotations.
Open Scope list_scope.
From Coq Require Import Classes.RelationClasses.
From Coq Require Import Setoid Morphisms.
From Velus Require Import Common.
Fresh name generation
The fresh monad (with memory) : generates new names and keeps
a record of each name generated along with some information
The file is structured as such:
- a signature FRESHKERNEL, which exposes the kernel features of the monad
- a functor FreshKernel which implements the previous signature,
and contains some gruesome definitions details that we prefer to hide
- a functor Fresh that includes FreshKernel and also offers some additional lemmas.
This module should be instanciated using an IDS module that contains, among other things,
the gensym function used for name generation
Module Type FRESHKERNEL
(
Import Ids :
IDS).
The Monad manipulates a state, which exposes a list of the identifiers generated
by the monad, paired with some data
Section st.
Parameter fresh_st :
Type ->
Type.
Context {
B :
Type}.
Parameter st_anns :
fresh_st B ->
list (
ident *
B).
Definition st_ids (
st :
fresh_st B) :=
map fst (
st_anns st).
End st.
Definition Fresh (
A B :
Type) :
Type :=
fresh_st B ->
A *
fresh_st B.
The state can be deemed as "valid".
st_valid_after st prefix aft means that the state only contains
identifier prefixed by prefix and that are distinct from the ones in aft.
This properties also ensures that all ids in the state are distinct
Section validity.
Context {
B :
Type}.
Parameter st_valid_after :
fresh_st B ->
ident ->
PS.t ->
Prop.
Conjecture st_valid_NoDup :
forall st prefix aft,
st_valid_after st prefix aft ->
NoDup (
st_ids st++
PSP.to_list aft).
Conjecture st_valid_PSeq :
forall st prefix aft1 aft2,
PS.eq aft1 aft2 ->
st_valid_after st prefix aft1 ->
st_valid_after st prefix aft2.
Conjecture st_valid_prefixed :
forall st prefix aft,
st_valid_after st prefix aft ->
Forall (
fun x =>
exists n,
x =
gensym prefix n) (
st_ids st).
End validity.
Sometimes we need to reuse allready existing identifiers.
st_valid_reuse st prefix aft reprefs reusable means that
the state only contains idents prefixed by either prefix or reprefs.
These idents are distinct from aft and reusable, but the ones in
reusable can also by reused by the function reuse_ident (see below)
while preserving this invariant
Section validity_reuse.
Context {
B :
Type}.
Parameter st_valid_reuse :
fresh_st B ->
ident ->
PS.t ->
PS.t ->
PS.t ->
Prop.
Conjecture st_valid_reuse_NoDup :
forall st prefix aft reprefs reusable,
st_valid_reuse st prefix aft reprefs reusable ->
NoDup (
st_ids st++
PSP.to_list aft++
PSP.to_list reusable).
Conjecture st_valid_reuse_PSeq :
forall st prefix aft reprefs re1 re2,
PS.eq re1 re2 ->
st_valid_reuse st prefix aft reprefs re1 ->
st_valid_reuse st prefix aft reprefs re2.
Conjecture st_valid_reuse_prefixed :
forall st prefix aft reprefs reu,
st_valid_reuse st prefix aft reprefs reu ->
Forall (
AtomOrGensym (
PS.add prefix reprefs)) (
st_ids st).
End validity_reuse.
st_follows forms an inclusion relation over the contents of the states.
We show below that every primimitive Fresh operation produces a new state
that follows the previous one
Section follows.
Context {
B :
Type}.
Parameter st_follows :
fresh_st B ->
fresh_st B ->
Prop.
Conjecture st_follows_refl :
Reflexive st_follows.
Conjecture st_follows_trans :
Transitive st_follows.
Conjecture st_follows_incl :
forall st st',
st_follows st st' ->
incl (
st_anns st) (
st_anns st').
End follows.
The initial state is empty.
An empty state is valid under a few assumption :
- the prefix used for generating must be different from the ones used previously.
- in the case of st_valid_reuse, the reusable and non-reusable idents must be distinct
When initializing
Section init.
Context {
B :
Type}.
Parameter init_st :
fresh_st B.
Conjecture init_st_anns :
st_anns init_st = [].
Conjecture init_st_valid :
forall prefix aft aftprefs,
~
PS.In prefix aftprefs ->
PS.For_all (
AtomOrGensym aftprefs)
aft ->
st_valid_after init_st prefix aft.
Conjecture init_st_valid_reuse :
forall prefix aft reprefs reusable,
NoDup (
PSP.to_list aft++
PSP.to_list reusable) ->
~
PS.In prefix reprefs ->
PS.For_all (
AtomOrGensym reprefs)
aft ->
PS.For_all (
AtomOrGensym reprefs)
reusable ->
st_valid_reuse init_st prefix aft reprefs reusable.
End init.
The central function for fresh identifier generation,
fresh_ident prefix d generates a new identifier prefixed by prefix and
associated with data d in the new state.
fresh_ident prefix d preserves validity as long as prefix is the correct one
Section fresh_ident.
Context {
B :
Type}.
Parameter fresh_ident :
ident ->
B ->
Fresh ident B.
Conjecture fresh_ident_anns :
forall pref b id st st',
fresh_ident pref b st = (
id,
st') ->
st_anns st' = (
id,
b)::(
st_anns st).
Conjecture fresh_ident_st_valid :
forall pref b id st st'
aft,
fresh_ident pref b st = (
id,
st') ->
st_valid_after st pref aft ->
st_valid_after st'
pref aft.
Conjecture fresh_ident_st_valid_reuse :
forall pref b id st st'
aft reprefs reusable,
fresh_ident pref b st = (
id,
st') ->
st_valid_reuse st pref aft reprefs reusable ->
st_valid_reuse st'
pref aft reprefs reusable.
Conjecture fresh_ident_st_follows :
forall pref b id st st',
fresh_ident pref b st = (
id,
st') ->
st_follows st st'.
End fresh_ident.
As stated above, it is also possible to reuse already existing identifiers,
that is adding it to the state.
reuse_ident x d adds x into the state, associated with d.
If this function is used, only the st_valid_reuse property can be preserved
Section reuse_ident.
Context {
B :
Type}.
Parameter reuse_ident :
ident ->
B ->
Fresh unit B.
Conjecture reuse_ident_anns :
forall b id st st',
reuse_ident id b st = (
tt,
st') ->
st_anns st' = (
id,
b)::(
st_anns st).
Conjecture reuse_ident_st_valid_reuse :
forall b id st st'
pref aft reprefs reusable,
~
PS.In id reusable ->
reuse_ident id b st = (
tt,
st') ->
st_valid_reuse st pref aft reprefs (
PS.add id reusable) ->
st_valid_reuse st'
pref aft reprefs reusable.
Conjecture reuse_ident_st_follows :
forall b id st st',
reuse_ident id b st = (
tt,
st') ->
st_follows st st'.
End reuse_ident.
Section ret.
Context {
A B :
Type}.
Parameter ret :
A ->
Fresh A B.
Conjecture ret_spec :
forall a st,
ret a st = (
a,
st).
End ret.
Section bind.
Context {
A A'
B :
Type}.
Parameter bind :
Fresh A B -> (
A ->
Fresh A'
B) ->
Fresh A'
B.
Conjecture bind_spec :
forall (
x :
Fresh A B) (
k :
A ->
Fresh A'
B)
st a'
st'',
(
bind x k)
st = (
a',
st'') <->
exists a,
exists st', (
x st = (
a,
st') /\
k a st' = (
a',
st'')).
End bind.
Section bind2.
Context {
A1 A2 A'
B :
Type}.
Parameter bind2 :
Fresh (
A1 *
A2)
B -> (
A1 ->
A2 ->
Fresh A'
B) ->
Fresh A'
B.
Conjecture bind2_spec :
forall (
x :
Fresh (
A1 *
A2)
B) (
k :
A1 ->
A2 ->
Fresh A'
B)
st a'
st'',
(
bind2 x k)
st = (
a',
st'') <->
exists a1,
exists a2,
exists st', (
x st = ((
a1,
a2),
st') /\
k a1 a2 st' = (
a',
st'')).
End bind2.
End FRESHKERNEL.
Module FreshKernel(
Import Ids :
IDS) :
FRESHKERNEL(
Ids).
Section st.
Definition fresh_st (
B :
Type) :
Type := (
ident *
list (
ident *
B)).
Context {
B :
Type}.
Definition st_anns (
st :
fresh_st B) :=
snd st.
Definition st_ids (
st :
fresh_st B) :=
map fst (
st_anns st).
End st.
Definition Fresh (
A B :
Type) :
Type :=
fresh_st B ->
A *
fresh_st B.
Section ret.
Context {
A B :
Type}.
Definition ret (
a :
A) :
Fresh A B :=
fun st => (
a,
st).
Fact ret_spec :
forall a st,
ret a st = (
a,
st).
Proof.
intros a st. reflexivity.
Qed.
End ret.
Section validity.
Context {
B :
Type}.
The state is valid if the next ident is greater than all generated idents,
and if there is no duplicates in generated idents
Definition st_valid_after (
st :
fresh_st B) (
pref :
ident) (
aft :
PS.t) :
Prop :=
let '(
n,
l) :=
st in
NoDupMembers l /\
Forall (
fun id =>
exists x,
id =
gensym pref x /\
Pos.lt x n) (
map fst l) /\
exists prefs,
~
PS.In pref prefs /\
PS.For_all (
AtomOrGensym prefs)
aft.
Fact AtomOrGensym_gensym_injective :
forall prefs pref x,
AtomOrGensym prefs (
gensym pref x) ->
PS.In pref prefs.
Proof.
Fact st_valid_NoDup :
forall st pref aft,
st_valid_after st pref aft ->
NoDup (
st_ids st++
PSP.to_list aft).
Proof.
Fact st_valid_PSeq :
forall st pref aft1 aft2,
PS.eq aft1 aft2 ->
st_valid_after st pref aft1 ->
st_valid_after st pref aft2.
Proof.
intros [n l] * Heq (?&?&?&?&?).
repeat (constructor; auto).
exists x. rewrite <- Heq; auto.
Qed.
Fact st_valid_prefixed :
forall st pref aft,
st_valid_after st pref aft ->
Forall (
fun x =>
exists n,
x =
gensym pref n) (
st_ids st).
Proof.
intros (?&?) * (?&?&?);
auto.
eapply Forall_impl; [|
eauto].
intros ? (?&
Hgen&
_);
subst;
eauto.
Qed.
End validity.
Section validity_reuse.
Context {
B :
Type}.
Definition st_valid_reuse (
st :
fresh_st B)
pref (
aft :
PS.t)
reprefs (
reusable :
PS.t) :
Prop :=
let '(
n,
l) :=
st in
NoDupMembers l /\
Forall (
AtomOrGensym (
PS.add pref reprefs)) (
map fst l) /\
Forall (
fun id =>
forall x,
id =
gensym pref x ->
Pos.lt x n) (
map fst l) /\
NoDup (
PSP.to_list aft++
PSP.to_list reusable) /\
PS.For_all (
AtomOrGensym reprefs)
aft /\
Forall (
fun id => ~
PS.In id aft) (
map fst l) /\
~
PS.In pref reprefs /\
PS.For_all (
AtomOrGensym reprefs)
reusable /\
Forall (
fun id => ~
PS.In id reusable) (
map fst l).
Fact st_valid_reuse_NoDup :
forall st pref aft reprefs reusable,
st_valid_reuse st pref aft reprefs reusable ->
NoDup (
st_ids st++
PSP.to_list aft++
PSP.to_list reusable).
Proof.
Fact st_valid_reuse_nIn :
forall st pref aft reprefs reusable,
st_valid_reuse st pref aft reprefs reusable ->
PS.For_all (
fun x => ~
In x (
st_ids st))
reusable.
Proof.
intros [? ?] * (?&?&?&?&?&?&?&?&
Hn2).
intros ?
Hin1 Hin2.
eapply Forall_forall in Hn2;
eauto.
Qed.
Fact st_valid_reuse_PSeq :
forall st pref aft reprefs re1 re2,
PS.eq re1 re2 ->
st_valid_reuse st pref aft reprefs re1 ->
st_valid_reuse st pref aft reprefs re2.
Proof.
intros [
n l] *
Heq (?&?&?&?&?&?&?&?&
Hn2).
repeat (
split;
auto).
1,2:
rewrite <-
Heq;
auto.
eapply Forall_impl; [|
eapply Hn2].
intros ? ?.
rewrite <-
Heq;
auto.
Qed.
Fact st_valid_reuse_prefixed :
forall st pref aft reprefs reu,
st_valid_reuse st pref aft reprefs reu ->
Forall (
AtomOrGensym (
PS.add pref reprefs)) (
st_ids st).
Proof.
intros [n l] * (?&?&?&?&?&?&?&?&?); auto.
Qed.
End validity_reuse.
Section follows.
Context {
B :
Type}.
Definition st_follows (
st st' :
fresh_st B) :=
incl (
snd st) (
snd st').
Fact st_follows_refl :
Reflexive st_follows.
Proof.
Fact st_follows_trans :
Transitive st_follows.
Proof.
Fact st_follows_incl :
forall st st',
st_follows st st' ->
incl (
st_anns st) (
st_anns st').
Proof.
intuition. Qed.
End follows.
Section init.
Context {
B :
Type}.
Definition init_st :
fresh_st B := (
xH, []).
Fact init_st_anns :
st_anns init_st = [].
Proof.
intros. reflexivity.
Qed.
Fact init_st_valid :
forall pref aft aftprefs,
~
PS.In pref aftprefs ->
PS.For_all (
AtomOrGensym aftprefs)
aft ->
st_valid_after init_st pref aft.
Proof.
intros *
Hnin Hprefs.
unfold init_st.
repeat (
constructor;
simpl;
eauto).
Qed.
Fact init_st_valid_reuse :
forall pref aft reprefs reusable,
NoDup (
PSP.to_list aft++
PSP.to_list reusable) ->
~
PS.In pref reprefs ->
PS.For_all (
AtomOrGensym reprefs)
aft ->
PS.For_all (
AtomOrGensym reprefs)
reusable ->
st_valid_reuse init_st pref aft reprefs reusable.
Proof.
intros *
Hnd Hpre1 Hpre2 Hpre3.
unfold init_st.
repeat split;
simpl;
auto.
constructor.
Qed.
End init.
Section fresh_ident.
Context {
B :
Type}.
Definition fresh_ident pref (
b :
B) :
Fresh ident B :=
fun '(
n,
l) =>
let id :=
gensym pref n in
(
id, (
Pos.succ n, (
id,
b)::
l)).
Fact fresh_ident_anns :
forall pref b id st st',
fresh_ident pref b st = (
id,
st') ->
st_anns st' = (
id,
b)::(
st_anns st).
Proof.
intros.
destruct st. inv H.
reflexivity.
Qed.
Fact fresh_ident_st_valid :
forall pref (
b :
B)
id st st'
aft,
fresh_ident pref b st = (
id,
st') ->
st_valid_after st pref aft ->
st_valid_after st'
pref aft.
Proof.
intros ? ? ? [
n l] [
n'
l']
aft Hfresh (
Hv1&
Hv2&
aftprefs&
Hv3&
Hv4).
simpl in Hfresh;
inv Hfresh.
repeat split;
simpl;
auto. 3:
exists aftprefs;
split;
auto. 1,2:
constructor;
auto.
-
rewrite fst_InMembers.
intro Hin.
eapply Forall_forall in Hv2 as (?&?&?);
eauto.
apply gensym_injective in H as (
_&?);
subst.
eapply Pos.lt_irrefl;
eauto.
-
exists n.
split;
auto.
apply Pos.lt_succ_diag_r.
-
eapply Forall_impl; [|
eauto].
intros ? (?&?&?);
subst.
exists x.
split;
auto.
etransitivity;
eauto.
apply Pos.lt_succ_diag_r.
Qed.
Fact fresh_ident_st_valid_reuse :
forall pref b id st st'
aft reprefs reusable,
fresh_ident pref b st = (
id,
st') ->
st_valid_reuse st pref aft reprefs reusable ->
st_valid_reuse st'
pref aft reprefs reusable.
Proof.
Fact fresh_ident_st_follows :
forall pref (
b :
B)
id st st',
fresh_ident pref b st = (
id,
st') ->
st_follows st st'.
Proof.
intros ??? [
n l] [
n'
l']
Hfresh.
simpl in *;
inv Hfresh;
simpl.
unfold st_follows in *;
simpl in *.
apply incl_tl.
reflexivity.
Qed.
End fresh_ident.
Section reuse_ident.
Context {
B :
Type}.
Definition reuse_ident (
id :
ident) (
b :
B) :
Fresh unit B :=
fun '(
n,
l) => (
tt, (
n, (
id,
b)::
l)).
Fact reuse_ident_anns :
forall b id st st',
reuse_ident id b st = (
tt,
st') ->
st_anns st' = (
id,
b)::(
st_anns st).
Proof.
intros b id [
n l] [
n'
l']
H.
unfold reuse_ident in H.
inv H.
reflexivity.
Qed.
Fact reuse_ident_st_valid_reuse :
forall b id st st'
pref aft reprefs reusable,
~
PS.In id reusable ->
reuse_ident id b st = (
tt,
st') ->
st_valid_reuse st pref aft reprefs (
PS.add id reusable) ->
st_valid_reuse st'
pref aft reprefs reusable.
Proof with
Fact reuse_ident_st_follows :
forall b id st st',
reuse_ident id b st = (
tt,
st') ->
st_follows st st'.
Proof.
End reuse_ident.
Section bind.
Context {
A A'
B :
Type}.
Definition bind (
x :
Fresh A B) (
k :
A ->
Fresh A'
B) :
Fresh A'
B :=
fun st =>
let '(
a,
st') :=
x st in k a st'.
Lemma bind_spec :
forall (
x :
Fresh A B) (
k :
A ->
Fresh A'
B)
st a'
st'',
(
bind x k)
st = (
a',
st'') <->
exists a,
exists st', (
x st = (
a,
st') /\
k a st' = (
a',
st'')).
Proof.
intros x k st a'
st''.
split;
intros.
-
unfold bind in H.
destruct (
x st)
as [
a st'].
exists a.
exists st'.
split;
auto.
-
destruct H as [
a [
st' [
H1 H2]]].
unfold bind.
rewrite H1.
assumption.
Qed.
End bind.
Section bind2.
Context {
A1 A2 A'
B :
Type}.
Definition bind2 (
x:
Fresh (
A1 *
A2)
B) (
k:
A1 ->
A2 ->
Fresh A'
B) :
Fresh A'
B :=
fun n =>
let '((
a1,
a2),
n') :=
x n in k a1 a2 n'.
Lemma bind2_spec :
forall (
x :
Fresh (
A1 *
A2)
B) (
k :
A1 ->
A2 ->
Fresh A'
B)
st a'
st'',
(
bind2 x k)
st = (
a',
st'') <->
exists a1,
exists a2,
exists st', (
x st = ((
a1,
a2),
st') /\
k a1 a2 st' = (
a',
st'')).
Proof.
intros x k st a'
st''.
split;
intros.
-
unfold bind2 in H.
destruct (
x st)
as [[
a1 a2]
st'].
exists a1.
exists a2.
exists st'.
split;
auto.
-
destruct H as [
a1 [
a2 [
st' [
H1 H2]]]].
unfold bind2.
rewrite H1.
assumption.
Qed.
End bind2.
End FreshKernel.
Module Fresh(
Ids :
IDS).
Module Ker :=
FreshKernel(
Ids).
Include Ker.
Section Instances.
Context {
B :
Type}.
Global Instance st_follows_Reflexive :
Reflexive (@
st_follows B) :=
st_follows_refl.
Global Instance st_follows_Transitive :
Transitive (@
st_follows B) :=
st_follows_trans.
Global Add Parametric Morphism st pref aft reprefs : (@
st_valid_reuse B st pref aft reprefs)
with signature @
PS.eq ==>
Basics.impl
as st_valid_reuse_PSeq_Proper.
Proof.
Global Instance st_valid_after_Proper :
Proper (@
eq (@
fresh_st B) ==> @
eq ident ==>
PS.Equal ==> @
Basics.impl)
st_valid_after.
Proof.
intros ? ? ? ? ? ? ? ?
Heq Hfresh;
subst.
eapply st_valid_PSeq;
eauto.
Qed.
End Instances.
Module Facts.
Section st.
Context {
B :
Type}.
Fact st_anns_ids_In :
forall (
st :
fresh_st B)
id,
(
exists b,
In (
id,
b) (
st_anns st)) <->
In id (
st_ids st).
Proof.
intros.
split;
intros.
-
destruct H as [
b H].
unfold st_ids.
rewrite in_map_iff.
exists (
id,
b);
auto.
-
unfold st_ids in H.
rewrite in_map_iff in H.
destruct H as [[?
b] [?
H]];
simpl in *;
subst.
exists b.
assumption.
Qed.
End st.
Section st_valid_after.
Context {
B :
Type}.
Fact st_valid_after_NoDupMembers {
C} :
forall (
st :
fresh_st B)
pref (
vars :
list (
ident *
C)),
NoDupMembers vars ->
st_valid_after st pref (
PSP.of_list (
map fst vars)) ->
NoDup (
map fst vars ++
st_ids st).
Proof.
End st_valid_after.
Section st_valid_reuse.
Context {
B :
Type}.
Fact st_valid_reuse_nIn :
forall (
st :
fresh_st B)
pref aft reprefs reusable,
st_valid_reuse st pref aft reprefs reusable ->
PS.For_all (
fun x => ~
In x (
st_ids st))
reusable.
Proof.
Fact st_valid_reuse_NoDupMembers {
C} :
forall (
st :
fresh_st B)
pref (
vars :
list (
ident *
C))
reprefs reusable,
NoDupMembers vars ->
st_valid_reuse st pref (
PSP.of_list (
map fst vars))
reprefs reusable ->
NoDup (
map fst vars ++
st_ids st).
Proof.
End st_valid_reuse.
Section fresh_ident.
Context {
B :
Type}.
Fact fresh_ident_In :
forall pref (
b :
B)
id st st',
fresh_ident pref b st = (
id,
st') ->
In (
id,
b) (
st_anns st').
Proof.
Corollary fresh_ident_Inids :
forall pref (
b :
B)
id st st',
fresh_ident pref b st = (
id,
st') ->
In id (
st_ids st').
Proof.
Fact fresh_ident_vars_perm :
forall pref (
b :
B)
id st st',
fresh_ident pref b st = (
id,
st') ->
Permutation (
id::(
st_ids st)) (
st_ids st').
Proof.
Fact fresh_ident_nIn :
forall pref (
b :
B)
id st st'
aft,
st_valid_after st pref aft ->
fresh_ident pref b st = (
id,
st') ->
~
List.In id (
st_ids st).
Proof.
Fact fresh_ident_reuse_nIn :
forall pref (
b :
B)
id st st'
aft reprefs reusable,
st_valid_reuse st pref aft reprefs reusable ->
fresh_ident pref b st = (
id,
st') ->
~
List.In id (
st_ids st).
Proof.
Fact fresh_ident_nIn' :
forall pref (
b :
B)
id st st'
aft,
st_valid_after st pref aft ->
fresh_ident pref b st = (
id,
st') ->
~
PS.In id aft.
Proof.
Fact fresh_ident_nIn'' :
forall pref (
b :
B)
id st st'
aft,
st_valid_after st pref (
PSP.of_list aft) ->
fresh_ident pref b st = (
id,
st') ->
~
In id (
aft ++
st_ids st).
Proof.
End fresh_ident.
Section reuse_ident.
Context {
B :
Type}.
Fact reuse_ident_In :
forall (
b :
B)
id st st',
reuse_ident id b st = (
tt,
st') ->
In (
id,
b) (
st_anns st').
Proof.
Fact reuse_ident_vars_perm :
forall (
b :
B)
id st st',
reuse_ident id b st = (
tt,
st') ->
Permutation (
id::(
st_ids st)) (
st_ids st').
Proof.
End reuse_ident.
End Facts.
Module Tactics.
Ltac inv_bind :=
simpl in *;
match goal with
|
H :
context c [
ret _ _] |-
_ =>
rewrite ret_spec in H
|
H : (
_,
_) = (
_,
_) |-
_ =>
inv H
|
H :
bind _ _ _ = (
_,
_) |-
_ =>
apply bind_spec in H;
destruct H as [? [? [? ?]]];
simpl in *
|
H :
bind2 _ _ _ = (
_,
_) |-
_ =>
apply bind2_spec in H;
destruct H as [? [? [? [? ?]]]];
simpl in *
| |-
context c [
ret _ _] =>
rewrite ret_spec
| |-
bind _ _ _ = (
_,
_) =>
rewrite bind_spec
| |-
bind2 _ _ _ = (
_,
_) =>
rewrite bind2_spec
end.
End Tactics.
Module Notations.
do notation, inspired by CompCert's error monad
Notation "'
do'
X <-
A ;
B" :=
(
bind A (
fun X =>
B))
(
at level 200,
X ident,
A at level 100,
B at level 200):
fresh_monad_scope.
Notation "'
do' (
X ,
Y ) <-
A ;
B" :=
(
bind2 A (
fun X Y =>
B))
(
at level 200,
X ident,
Y ident,
A at level 100,
B at level 200):
fresh_monad_scope.
End Notations.
Section map_bind.
Import Tactics Notations.
Open Scope fresh_monad_scope.
Context {
A A1 B :
Type}.
Variable k :
A ->
Fresh A1 B.
Fixpoint map_bind a :=
match a with
|
nil =>
ret nil
|
hd::
tl =>
do a1 <-
k hd;
do a1s <-
map_bind tl;
ret (
a1::
a1s)
end.
Fact map_bind_values :
forall a st a1s st',
map_bind a st = (
a1s,
st') ->
Forall2 (
fun a a1 =>
exists st'',
exists st''',
k a st'' = (
a1,
st'''))
a a1s.
Proof.
induction a; intros st a1s st' Hfold; simpl in *; repeat inv_bind.
- constructor.
- specialize (IHa _ _ _ H0).
constructor; eauto.
Qed.
Fact map_bind_st_valid :
forall a a1s st st'
pref aft,
map_bind a st = (
a1s,
st') ->
Forall (
fun a =>
forall a1 st st',
k a st = (
a1,
st') ->
st_valid_after st pref aft ->
st_valid_after st'
pref aft)
a ->
st_valid_after st pref aft ->
st_valid_after st'
pref aft.
Proof.
induction a; intros * Hmap Hforall Hvalid;
simpl in *; repeat inv_bind; auto.
inv Hforall. eapply IHa; eauto.
Qed.
Fact map_bind_st_follows :
forall a a1s st st',
map_bind a st = (
a1s,
st') ->
Forall (
fun a =>
forall a1 st st',
k a st = (
a1,
st') ->
st_follows st st')
a ->
st_follows st st'.
Proof.
induction a; intros * Hmap Hforall;
simpl in *; repeat inv_bind; auto.
- reflexivity.
- inv Hforall.
etransitivity; eauto.
Qed.
End map_bind.
Section map_bind2.
Import Tactics Notations.
Open Scope fresh_monad_scope.
Context {
A A1 A2 B :
Type}.
Variable k :
A ->
Fresh (
A1 *
A2)
B.
Fixpoint map_bind2 a :=
match a with
|
nil =>
ret (
nil,
nil)
|
hd::
tl =>
do (
a1,
a2) <-
k hd;
do (
a1s,
a2s) <-
map_bind2 tl;
ret (
a1::
a1s,
a2::
a2s)
end.
Fact map_bind2_values :
forall a st a1s a2s st',
map_bind2 a st = (
a1s,
a2s,
st') ->
Forall3 (
fun a a1 a2 =>
exists st'',
exists st''',
k a st'' = (
a1,
a2,
st'''))
a a1s a2s.
Proof.
induction a; intros st a1s a2s st' Hfold; simpl in *; repeat inv_bind.
- constructor.
- specialize (IHa _ _ _ _ H0).
constructor; eauto.
Qed.
Fact map_bind2_st_valid :
forall a a1s a2s st st'
pref aft,
map_bind2 a st = (
a1s,
a2s,
st') ->
Forall (
fun a =>
forall a1 a2 st st',
k a st = (
a1,
a2,
st') ->
st_valid_after st pref aft ->
st_valid_after st'
pref aft)
a ->
st_valid_after st pref aft ->
st_valid_after st'
pref aft.
Proof.
induction a; intros * Hmap Hforall Hvalid;
simpl in *; repeat inv_bind; auto.
inv Hforall. eapply IHa; eauto.
Qed.
Fact map_bind2_st_valid_reuse :
forall a a1s a2s st st'
pref aft reprefs reu,
map_bind2 a st = (
a1s,
a2s,
st') ->
Forall (
fun a =>
forall a1 a2 st st',
k a st = (
a1,
a2,
st') ->
st_valid_reuse st pref aft reprefs reu ->
st_valid_reuse st'
pref aft reprefs reu)
a ->
st_valid_reuse st pref aft reprefs reu ->
st_valid_reuse st'
pref aft reprefs reu.
Proof.
induction a; intros * Hmap Hforall Hvalid;
simpl in *; repeat inv_bind; auto.
inv Hforall. eapply IHa; eauto.
Qed.
Fact map_bind2_st_follows :
forall a a1s a2s st st',
map_bind2 a st = (
a1s,
a2s,
st') ->
Forall (
fun a =>
forall a1 a2 st st',
k a st = (
a1,
a2,
st') ->
st_follows st st')
a ->
st_follows st st'.
Proof.
induction a; intros a1s a2s st st' Hmap Hforall;
simpl in *; repeat inv_bind; auto.
- reflexivity.
- inv Hforall.
etransitivity; eauto.
Qed.
End map_bind2.
Hint Resolve fresh_ident_st_valid.
Hint Resolve fresh_ident_st_valid_reuse.
Hint Resolve fresh_ident_st_follows.
Hint Resolve reuse_ident_st_valid_reuse.
Hint Resolve reuse_ident_st_follows.
Hint Resolve st_follows_incl.
Hint Resolve map_bind2_st_valid.
Hint Resolve map_bind2_st_follows.
End Fresh.