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)).

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).