Definition respectful {X} (P : dist X -> Prop) : Prop :=
  forall d1 d2, d1 ==d d2 -> P d1 <-> P d2.

(* Specifications: *)
Lemma uniform_respectful {X} `{EqDec X} : respectful uniform.
Lemma monad_left_id_equiv {X Y} (x : X) (f : X -> dist Y) : mbind (mreturn x) f ==d (f x).
Lemma monad_right_id_equiv {X} (m : dist X) : mbind m mreturn ==d m.
Lemma bind_assoc_equiv {X Y Z} (m : dist X) (f : X -> dist Y) (g : Y -> dist Z) : (mbind (mbind m f) g) ==d (mbind m (fun x => mbind (f x) g)).
Lemma bind_ext_equiv {X Y} (m : dist X) (f g : X -> dist Y) : (forall x, (f x) ==d (g x)) -> (mbind m f) ==d (mbind m g).
Lemma monad_left_id_resp {X Y} (x : X) (f : X -> dist Y) (P : dist Y -> Prop) : respectful P -> P (mbind (mreturn x) f) <-> P (f x).
Lemma monad_right_id_resp {X} (m : dist X) (P : dist X -> Prop) : respectful P -> P (mbind m mreturn) <-> P m.
Lemma bind_assoc_resp {X Y Z} (P : dist Z -> Prop) (m : dist X) (f : X -> dist Y) (g : Y -> dist Z) : respectful P -> P (mbind (mbind m f) g) <-> P (mbind m (fun x => mbind (f x) g)).
Lemma bind_ext_resp {X Y} (m : dist X) (f g : X -> dist Y) (P : dist Y -> Prop) : respectful P -> (forall x, (f x) ==d (g x)) -> P (mbind m f) <-> P (mbind m g).
Lemma hoare_bind {X Y} (Pre : dist PosMap -> Prop) (Mid : dist (X * PosMap) -> Prop) (Post : dist (Y * PosMap) -> Prop) (m : M X) (f : X -> M Y) : respectful Post -> hoare Pre Mid m -> (forall d, Mid d -> Post (f_apply f d)) -> hoare Pre Post (mbind m f).
Lemma sigma_dist_coin_flip f : sigma_dist coin_flip f == f true (1/2) + f false (1/2).
Lemma NoDup_Fin_enum n : NoDup (Fin_enum n).
Lemma NoDup_enum {X} `{Finite X} : NoDup (enum : list X).
Lemma filter_split {X} (part : X -> bool) (f : X -> Q) : forall xs, Qsum (map f xs) == Qsum (map f (filter part xs)) + Qsum (map f (filter (fun x => negb (part x)) xs)).
Lemma f_equal_plus x y z : x == y -> z + x == z + y.
Lemma Qsum_ext {X} (xs : list X) (f g : X -> Q) : (forall x, In x xs -> f x == g x) -> Qsum (map f xs) == Qsum (map g xs).
Lemma filter_filter {X} (p q : X -> bool) (xs : list X) : filter p (filter q xs) = filter (fun x => p x && q x) xs.
Lemma part_lemma {X Y} (part : X -> Y -> bool) (f : Y -> Q) (xs : list X) : (forall x x' y, part x y = true -> part x' y = true -> x = x') -> NoDup xs -> forall ys : list Y, (forall y, In y ys -> exists x, In x xs /\ part x y = true) -> Qsum (map f ys) == Qsum (map (fun x => Qsum (map f (filter (part x) ys))) xs).
Lemma sum_dist_Qsum {X} (l : list (X * Q)) : sum_dist l == Qsum (map snd l).
Lemma Qsum_list_repeat : forall (n : nat) (x : Q), Qsum (repeat x n) == (x * Q_of_nat n).
Lemma length_enum {X} `{Finite X} : length enum = card X.
Lemma filter_dist_filter {X} (l : list (X * Q)) (p : X -> bool) : filter_dist l p = filter (fun pr => p (fst pr)) l.
Lemma uniform_card_rev {X} `{Finite X} (d : dist X) (x : X) : uniform d -> eval_dist d (Classes.eqb x) == 1 / Q_of_nat (card X).
Lemma eval_dist_sumFQ {X} `{Finite X} (d : dist X) (E : X -> bool) : eval_dist d E == sumFQ (fun x => indicate (E x) * eval_dist d (Classes.eqb x)).
Lemma uniform_count {X} `{Finite X} (d : dist X) (E : X -> bool) : uniform d -> eval_dist d E == Q_of_nat (count E) / Q_of_nat (card X).
Lemma uniform_respectful {X} `{EqDec X} : respectful uniform.
Lemma monad_left_id_equiv {X Y} (x : X) (f : X -> dist Y) : mbind (mreturn x) f ==d (f x).
Lemma monad_right_id_equiv {X} (m : dist X) : mbind m mreturn ==d m.
Lemma bind_assoc_equiv {X Y Z} (m : dist X) (f : X -> dist Y) (g : Y -> dist Z) : (mbind (mbind m f) g) ==d (mbind m (fun x => mbind (f x) g)).
Lemma bind_ext_equiv {X Y} (m : dist X) (f g : X -> dist Y) : (forall x, (f x) ==d (g x)) -> (mbind m f) ==d (mbind m g).
Lemma monad_left_id_resp {X Y} (x : X) (f : X -> dist Y) (P : dist Y -> Prop) : respectful P -> P (mbind (mreturn x) f) <-> P (f x).
Lemma monad_right_id_resp {X} (m : dist X) (P : dist X -> Prop) : respectful P -> P (mbind m mreturn) <-> P m.
Lemma bind_assoc_resp {X Y Z} (P : dist Z -> Prop) (m : dist X) (f : X -> dist Y) (g : Y -> dist Z) : respectful P -> P (mbind (mbind m f) g) <-> P (mbind m (fun x => mbind (f x) g)).
Lemma bind_ext_resp {X Y} (m : dist X) (f g : X -> dist Y) (P : dist Y -> Prop) : respectful P -> (forall x, (f x) ==d (g x)) -> P (mbind m f) <-> P (mbind m g).
Lemma hoare_bind {X Y} (Pre : dist PosMap -> Prop) (Mid : dist (X * PosMap) -> Prop) (Post : dist (Y * PosMap) -> Prop) (m : M X) (f : X -> M Y) : respectful Post -> hoare Pre Mid m -> (forall d, Mid d -> Post (f_apply f d)) -> hoare Pre Post (mbind m f).
Lemma sigma_dist_coin_flip f : sigma_dist coin_flip f == f true (1/2) + f false (1/2).
Lemma NoDup_Fin_enum n : NoDup (Fin_enum n).
Lemma NoDup_enum {X} `{Finite X} : NoDup (enum : list X).
Lemma filter_split {X} (part : X -> bool) (f : X -> Q) : forall xs, Qsum (map f xs) == Qsum (map f (filter part xs)) + Qsum (map f (filter (fun x => negb (part x)) xs)).
Lemma f_equal_plus x y z : x == y -> z + x == z + y.
Lemma Qsum_ext {X} (xs : list X) (f g : X -> Q) : (forall x, In x xs -> f x == g x) -> Qsum (map f xs) == Qsum (map g xs).
Lemma filter_filter {X} (p q : X -> bool) (xs : list X) : filter p (filter q xs) = filter (fun x => p x && q x) xs.
Lemma part_lemma {X Y} (part : X -> Y -> bool) (f : Y -> Q) (xs : list X) : (forall x x' y, part x y = true -> part x' y = true -> x = x') -> NoDup xs -> forall ys : list Y, (forall y, In y ys -> exists x, In x xs /\ part x y = true) -> Qsum (map f ys) == Qsum (map (fun x => Qsum (map f (filter (part x) ys))) xs).
Lemma sum_dist_Qsum {X} (l : list (X * Q)) : sum_dist l == Qsum (map snd l).
Lemma Qsum_list_repeat : forall (n : nat) (x : Q), Qsum (repeat x n) == (x * Q_of_nat n).
Lemma length_enum {X} `{Finite X} : length enum = card X.
Lemma filter_dist_filter {X} (l : list (X * Q)) (p : X -> bool) : filter_dist l p = filter (fun pr => p (fst pr)) l.
Lemma uniform_card_rev {X} `{Finite X} (d : dist X) (x : X) : uniform d -> eval_dist d (Classes.eqb x) == 1 / Q_of_nat (card X).
Lemma eval_dist_sumFQ {X} `{Finite X} (d : dist X) (E : X -> bool) : eval_dist d E == sumFQ (fun x => indicate (E x) * eval_dist d (Classes.eqb x)).
Lemma uniform_count {X} `{Finite X} (d : dist X) (E : X -> bool) : uniform d -> eval_dist d E == Q_of_nat (count E) / Q_of_nat (card X).