Definition eval_dist {X} (mu : dist X) (f : X -> bool) : Q :=
  sum_dist (filter_dist (dist_pmf mu) f).Goal eval_dist coin_flip_two (fun '(p,q) => andb p q) = 1 / 4.(* mapM :: Monad m => (a -> m b) -> t a -> m (t b) *)

Definition mapM {A B M} `{Monad M} (f : A -> M B) (l : list (M A)) 
    :list (M B) := 
  (List.map
     (fun s => mbind s f) l).Definition distr_eqv {X} d d' : Prop :=
  forall (E : X -> bool), 
  Qeq (eval_dist d E) (eval_dist d' E).(* Definition acc_list_1 {C : Config} (arg_list : list (block_id * operation)) (s : state) : *)
(*   list (dist path). *)
(*   pose (List.map (fun '(bid, op) => access bid op) arg_list). *)
(*   refine (List.map _ l). *)
(*   intros prm. *)
(*   specialize (prm s). *)
(*   pose (map fst prm). *)
(*   pose (map fst d). *)
(*   exact d0. *)
(* Defined. *)

Definition acc_dist_list {C : Config}
  (arg_list : list (block_id * operation)) : Poram (list path) :=
  let l := List.map (fun '(bid, op) => access bid op) arg_list in
  let p := sequence l in
  monad_map (List.map fst) p.Definition get_dist_list_bool {C : Config}
  (arg_list : list (block_id * operation))(s : state) : dist (list bool) :=
  monad_map (@List.concat bool) (monad_map fst ((acc_dist_list arg_list) s)).

(* Specifications: *)
Lemma state_plift_map : forall {X Y} (Pre Post: state -> Prop) (P : Y -> Prop) (f : X -> Y) (m : Poram X), state_plift Pre Post (fun x => P (f x)) m -> state_plift Pre Post P (monad_map f m).
Lemma sequence_length : forall {S A M} `{PredLift M} (Pre : S -> Prop)(l : list (StateT S M A)) , let n := List.length l in state_plift Pre Pre (fun l' => List.length l' = n) (sequence l).
Lemma state_plift_Forall : forall {S A M} `{PredLift M} (Pre : S -> Prop) (P : A -> Prop) (l : list (StateT S M A)), Forall (state_plift Pre Pre P) l -> state_plift Pre Pre (Forall P) (sequence l).
Lemma state_plift_P_weakening : forall {S A M} `{PredLift M} (Pre : S -> Prop)(P Q: A -> Prop) s, (forall x, P x -> Q x) -> state_plift Pre Pre P s -> state_plift Pre Pre Q s.
Lemma state_plift_P_split : forall {C : Config} {S M X} `{PredLift M} (P Q : X -> Prop) (Pre Post: S -> Prop) (s : StateT S M X), state_plift Pre Post P s /\ state_plift Pre Post Q s -> state_plift Pre Post (fun x => (P x /\ Q x)) s.
Lemma acc_dist_list_length : forall {C : Config} (arg_list : list (block_id * operation)), state_plift well_formed well_formed (fun l => List.length l = List.length arg_list /\ (Forall (fun l' => List.length l' = LOP) l)) (acc_dist_list arg_list).
Lemma state_plift_map : forall {X Y} (Pre Post: state -> Prop) (P : Y -> Prop) (f : X -> Y) (m : Poram X), state_plift Pre Post (fun x => P (f x)) m -> state_plift Pre Post P (monad_map f m).
Lemma sequence_length : forall {S A M} `{PredLift M} (Pre : S -> Prop)(l : list (StateT S M A)) , let n := List.length l in state_plift Pre Pre (fun l' => List.length l' = n) (sequence l).
Lemma state_plift_Forall : forall {S A M} `{PredLift M} (Pre : S -> Prop) (P : A -> Prop) (l : list (StateT S M A)), Forall (state_plift Pre Pre P) l -> state_plift Pre Pre (Forall P) (sequence l).
Lemma state_plift_P_weakening : forall {S A M} `{PredLift M} (Pre : S -> Prop)(P Q: A -> Prop) s, (forall x, P x -> Q x) -> state_plift Pre Pre P s -> state_plift Pre Pre Q s.
Lemma state_plift_P_split : forall {C : Config} {S M X} `{PredLift M} (P Q : X -> Prop) (Pre Post: S -> Prop) (s : StateT S M X), state_plift Pre Post P s /\ state_plift Pre Post Q s -> state_plift Pre Post (fun x => (P x /\ Q x)) s.
Lemma acc_dist_list_length : forall {C : Config} (arg_list : list (block_id * operation)), state_plift well_formed well_formed (fun l => List.length l = List.length arg_list /\ (Forall (fun l' => List.length l' = LOP) l)) (acc_dist_list arg_list).