(* 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.

(* Specifications: *)
Theorem foldBody_option_spec :
forall (A B C D: Set)(eqda : EqDec A)(eqdb : EqDec B) (c1 : A -> C -> Comp (option A)) (c2 : B -> D -> Comp (option B)) (post : A -> B -> Prop) (pre1 : A -> B -> Prop) (pre2 : C -> D -> Prop),
(forall a b c d,
pre1 a b -> pre2 c d -> comp_spec (opt_pred post) (c1 a c) (c2 b d)) ->
forall opt_a opt_b c d,
opt_pred pre1 opt_a opt_b ->
pre2 c d ->
comp_spec
(opt_pred post)
(foldBody_option _ c1 opt_a c)
(foldBody_option _ c2 opt_b d).