Ltac simp_in_support := 
  unfold setLet in *;
  match goal with
    | [H : In _ (getSupport (Bind _ _)) |- _ ] =>
      apply getSupport_Bind_In in H; destruct_exists; intuition
    | [H : In _ (getSupport (if ?t then _ else _)) |- _ ] => let x := fresh "x" in remember t as x; destruct x
    | [H : In _ (getSupport (ret _)) |- _ ] => apply getSupport_In_Ret in H; try pairInv; subst
(*     | [H : false = inRange _ _ |- _] => symmetry in H *)
    | [H : true = negb ?t |- _ ] => let x := fresh "x" in remember t as x; destruct x; simpl in H; try discriminate
  end.(* evalDist is a denotational semantics that produces a distribution instead of a value. *)

Definition Distribution(A : Set) := A -> Rat.Definition indicator(A : Set)(P : A -> bool) :=
  fun a => if (P a) then rat1 else rat0.Fixpoint evalDist(A : Set)(c : Comp A) : Distribution A :=
  match c with
    | Ret eqd a => fun a' => if (eqd a a') then 1 else 0
    | Bind c1 c2 => fun a => 
      sumList (getSupport c1) (fun b => (evalDist c1 b) * (evalDist (c2 b) a))
    | Rnd n => fun v => 1 / (expnat 2 n)
    | Repeat c P => fun a => (indicator P a) * (ratInverse (sumList (filter P (getSupport c)) (evalDist c))) * (evalDist c a)
  end.

(* Specifications: *)
Lemma getSupport_NoDup : forall (A : Set)(c : Comp A), NoDup (getSupport c).
Lemma filter_not_In : forall (A : Set)(ls : list A)(P : A -> bool) a, (~In a ls) \/ P a = false <-> ~In a (filter P ls).
Theorem getSupport_correct : forall (A : Set)(c : Comp A), Support (getSupport c)(evalDist c).