Definition indicate (b : bool) : Q :=
  if b then 1 else 0.Definition indicate_nat (b : bool) : nat :=
  if b then 1 else O.

(* Specifications: *)
Lemma eval_ret {X} (x : X) (E : X -> bool) : eval_dist (mreturn x) E == indicate (E x).
Lemma eval_dist_sigma_dist {X} (d : dist X) (E : X -> bool) : eval_dist d E == sigma_dist d (fun x q => q * indicate (E x)).
Lemma filter_dist_app {X} (xs xs' : list (X * Q)) (p : X -> bool) : filter_dist (xs ++ xs') p = filter_dist xs p ++ filter_dist xs' p.
Lemma filter_dist_flat_map {X Y} (f : X -> list (Y * Q)) (xs : list X) (p : Y -> bool) : filter_dist (flat_map f xs) p = flat_map (fun x => filter_dist (f x) p) xs.
Lemma sum_dist_app {X} (l l' : list (X * Q)) : sum_dist (l ++ l') == sum_dist l + sum_dist l'.
Lemma sum_dist_flat_map {X Y} (f : X -> list (Y * Q)) (xs : list X) : sum_dist (flat_map f xs) == Qsum (map (fun x => sum_dist (f x)) xs).
Lemma filter_dist_update_probs {X} (l : list (X * Q)) (q : Q) (p : X -> bool) : filter_dist (update_probs q l) p = update_probs q (filter_dist l p).
Lemma sum_dist_update_probs {X} (l : list (X * Q)) (q : Q) : sum_dist (update_probs q l) == q * sum_dist l.
Lemma eval_bind {X Y} (m : dist X) (f : X -> dist Y) (E : Y -> bool) : eval_dist (mbind m f) E == sigma_dist m (fun x q => q * eval_dist (f x) E).
Lemma card_rev_uniform {X} `{Finite X} (d : dist X) : (forall x, eval_dist d (Classes.eqb x) == 1 / Q_of_nat (card X)) -> uniform d.
Lemma Qsum_scalar {X} (xs : list X) (f : X -> Q) (q : Q) : Qsum (map (fun x => q * f x) xs) == q * Qsum (map f xs).
Lemma eval_ret {X} (x : X) (E : X -> bool) : eval_dist (mreturn x) E == indicate (E x).
Lemma eval_dist_sigma_dist {X} (d : dist X) (E : X -> bool) : eval_dist d E == sigma_dist d (fun x q => q * indicate (E x)).
Lemma filter_dist_app {X} (xs xs' : list (X * Q)) (p : X -> bool) : filter_dist (xs ++ xs') p = filter_dist xs p ++ filter_dist xs' p.
Lemma filter_dist_flat_map {X Y} (f : X -> list (Y * Q)) (xs : list X) (p : Y -> bool) : filter_dist (flat_map f xs) p = flat_map (fun x => filter_dist (f x) p) xs.
Lemma sum_dist_app {X} (l l' : list (X * Q)) : sum_dist (l ++ l') == sum_dist l + sum_dist l'.
Lemma sum_dist_flat_map {X Y} (f : X -> list (Y * Q)) (xs : list X) : sum_dist (flat_map f xs) == Qsum (map (fun x => sum_dist (f x)) xs).
Lemma filter_dist_update_probs {X} (l : list (X * Q)) (q : Q) (p : X -> bool) : filter_dist (update_probs q l) p = update_probs q (filter_dist l p).
Lemma sum_dist_update_probs {X} (l : list (X * Q)) (q : Q) : sum_dist (update_probs q l) == q * sum_dist l.
Lemma eval_bind {X Y} (m : dist X) (f : X -> dist Y) (E : Y -> bool) : eval_dist (mbind m f) E == sigma_dist m (fun x q => q * eval_dist (f x) E).
Lemma card_rev_uniform {X} `{Finite X} (d : dist X) : (forall x, eval_dist d (Classes.eqb x) == 1 / Q_of_nat (card X)) -> uniform d.
Lemma Qsum_scalar {X} (xs : list X) (f : X -> Q) (q : Q) : Qsum (map (fun x => q * f x) xs) == q * Qsum (map f xs).