(* Use of this source code is governed by the license described	* * in the LICENSE file at the root of the source tree.		*)
(* Operations that fold and map a computation over a list, and related theory. *)
Set Implicit Arguments.
Local Open Scope list_scope.
(* Definitions for fold, map etc.   These should probably go somewhere else. *)
(* Fold a computation over a list *)
Fixpoint compFold(A B : Set)(eqd : EqDec B)(f : B -> A -> Comp B)(init : B)(ls : list A) :=
match ls with
| nil => ret init
| a :: ls' =>
init' <-$ f init a;
compFold  _ f init' ls'
end.
(* foldBody_option is an adapter that allows you to fold a computation with signature B -> A -> Comp (option B) over a list of A, accumulating an option B. *)
Definition foldBody_option(A B : Set)(eqd : EqDec B)(f : B -> A -> Comp (option B))(b_opt : option B)(a : A) :=
match b_opt with
| None => ret None
| Some b =>
f b a
end.
Definition opt_pred(A B : Set)(P : A -> B -> Prop)(opt_a : option A)(opt_b : option B) :=
match opt_a with
| Some a =>
match opt_b with
| Some b => P a b
| None => False
end
| None =>
match opt_b with
| Some _ => False
| None => True
end
end.
intuition.
unfold foldBody_option.
unfold opt_pred in *.
destruct opt_a; destruct opt_b; intuition.
eapply comp_spec_ret; intuition.
Qed.
induction 1; intuition; simpl.
eapply comp_spec_ret; intuition.
eapply comp_spec_seq; eauto.
eapply foldBody_option_spec; eauto.
Qed.
(* Map a computation over a list. *)
Fixpoint compMap (A B : Set)(eqdb : EqDec B)(c : A -> Comp B)(ls : list A) : Comp (list B) :=
match ls with
| nil => ret nil
| a :: lsa' =>
b <-$ c a;
lsb' <-$ compMap _ c lsa';
ret (b :: lsb')
end.
intuition.
simpl.
intuition.
Qed.
intuition.
Qed.
intuition.
apply nil.
Qed.
induction ls; intuition.
unfold compMap.
prog_simp.
intuition.
simpl.
prog_inline_first.
Hint Resolve list_inhabited : inhabited.
eapply comp_spec_seq; intuition;
eauto with inhabited.
eapply comp_spec_eq_trans.
2:{
eapply comp_spec_seq_eq; eauto with inhabited.
eapply comp_spec_eq_refl.
intuition.
eapply comp_spec_seq_eq; eauto with inhabited.
intuition.
eapply comp_spec_eq_refl.
}
prog_swap_r.
prog_inline_first.
prog_skip.
Qed.
intuition.
eapply compMap_fission_eq; intuition.
simpl.
eapply comp_spec_eq_refl.
simpl.
prog_simp.
eapply comp_spec_ret.
congruence.
Qed.
induction ls; intuition.
unfold compMap.
prog_simp.
eapply comp_spec_eq_refl.
simpl.
prog_inline_first.
prog_at prog_inline rightc 1%nat.
simpl.
prog_at prog_ret rightc 2.
simpl.
prog_at prog_swap rightc 1%nat.
eapply comp_spec_eq_trans.
eapply comp_spec_seq_eq; intuition.
eapply comp_spec_eq_refl.
prog_inline_first.
do 2 prog_skip.
Qed.

Theorem fold_map_fission_spec :
forall (A E : Set)(P : A -> E -> Prop)(B D : Set)(eqdA : EqDec A)(c1 : A -> B -> Comp A)(ls_b : list B)(init_a : A)
(eqdD : EqDec D)(eqdE : EqDec E)(c2 : B -> Comp D)(c3 : E -> D -> Comp E)(init_e : E),
P init_a init_e ->
(forall a b e, P a e -> comp_spec P (c1 a b) (a0 <-$ c2 b; c3 e a0)) ->
comp_spec P
(compFold _ c1 init_a ls_b)
(ls_d <-$ (compMap _ c2 ls_b); compFold _ c3 init_e ls_d).