(*
Instance comp_eq_dec : forall (A : Set),
  Comp A ->
  EqDec A.

eapply comp_base_EqDec.
Qed.

Instance bind_EqDec : forall (B A : Set),
  Comp B ->
  (B -> Comp A) ->
  EqDec A.

intuition.
eapply comp_EqDec.
eapply X0.
eapply comp_base_exists.
eauto.
Qed.

*)



Fixpoint getSupport(A : Set)(c : Comp A) : list A :=
  match c with
    | Ret _ a => a :: nil
    | Bind c1 c2 => getUnique (flatten (map (fun b => (getSupport (c2 b))) (getSupport c1))) (bind_eq_dec c1 c2)
    | Rnd n => getAllBvectors n
    | Repeat c1 P => (filter P (getSupport c1))
  end.(* Only well-formed computations are guaranteed to terminate. *)
Inductive well_formed_comp : forall (A : Set), Comp A -> Prop :=
  | well_formed_Ret :
    forall (A : Set)(pf : eq_dec A)(a : A),
      well_formed_comp (Ret pf a)
  | well_formed_Bind : 
    forall (A B : Set)(c1 : Comp B)(c2 : B -> Comp A),
      well_formed_comp c1 ->
      (forall b, In b (getSupport c1) -> well_formed_comp (c2 b)) ->
      well_formed_comp (Bind c1 c2)
   | well_formed_Rnd : forall n,
     well_formed_comp (Rnd n)
   | well_formed_Repeat :
     forall (A : Set)(eqd : eq_dec A)(c : Comp A) P b,
      well_formed_comp c ->
      In b (filter P (getSupport c)) ->
      well_formed_comp (Repeat c P).(* Only well-formed computations are guaranteed to terminate. *)
Inductive well_formed_comp : forall (A : Set), Comp A -> Prop :=
  | well_formed_Ret :
    forall (A : Set)(pf : eq_dec A)(a : A),
      well_formed_comp (Ret pf a)
  | well_formed_Bind : 
    forall (A B : Set)(c1 : Comp B)(c2 : B -> Comp A),
      well_formed_comp c1 ->
      (forall b, In b (getSupport c1) -> well_formed_comp (c2 b)) ->
      well_formed_comp (Bind c1 c2)
   | well_formed_Rnd : forall n,
     well_formed_comp (Rnd n)
   | well_formed_Repeat :
     forall (A : Set)(eqd : eq_dec A)(c : Comp A) P b,
      well_formed_comp c ->
      In b (filter P (getSupport c)) ->
      well_formed_comp (Repeat c P).(* Only well-formed computations are guaranteed to terminate. *)
Inductive well_formed_comp : forall (A : Set), Comp A -> Prop :=
  | well_formed_Ret :
    forall (A : Set)(pf : eq_dec A)(a : A),
      well_formed_comp (Ret pf a)
  | well_formed_Bind : 
    forall (A B : Set)(c1 : Comp B)(c2 : B -> Comp A),
      well_formed_comp c1 ->
      (forall b, In b (getSupport c1) -> well_formed_comp (c2 b)) ->
      well_formed_comp (Bind c1 c2)
   | well_formed_Rnd : forall n,
     well_formed_comp (Rnd n)
   | well_formed_Repeat :
     forall (A : Set)(eqd : eq_dec A)(c : Comp A) P b,
      well_formed_comp c ->
      In b (filter P (getSupport c)) ->
      well_formed_comp (Repeat c P).(* Only well-formed computations are guaranteed to terminate. *)
Inductive well_formed_comp : forall (A : Set), Comp A -> Prop :=
  | well_formed_Ret :
    forall (A : Set)(pf : eq_dec A)(a : A),
      well_formed_comp (Ret pf a)
  | well_formed_Bind : 
    forall (A B : Set)(c1 : Comp B)(c2 : B -> Comp A),
      well_formed_comp c1 ->
      (forall b, In b (getSupport c1) -> well_formed_comp (c2 b)) ->
      well_formed_comp (Bind c1 c2)
   | well_formed_Rnd : forall n,
     well_formed_comp (Rnd n)
   | well_formed_Repeat :
     forall (A : Set)(eqd : eq_dec A)(c : Comp A) P b,
      well_formed_comp c ->
      In b (filter P (getSupport c)) ->
      well_formed_comp (Repeat c P).(* Only well-formed computations are guaranteed to terminate. *)
Inductive well_formed_comp : forall (A : Set), Comp A -> Prop :=
  | well_formed_Ret :
    forall (A : Set)(pf : eq_dec A)(a : A),
      well_formed_comp (Ret pf a)
  | well_formed_Bind : 
    forall (A B : Set)(c1 : Comp B)(c2 : B -> Comp A),
      well_formed_comp c1 ->
      (forall b, In b (getSupport c1) -> well_formed_comp (c2 b)) ->
      well_formed_comp (Bind c1 c2)
   | well_formed_Rnd : forall n,
     well_formed_comp (Rnd n)
   | well_formed_Repeat :
     forall (A : Set)(eqd : eq_dec A)(c : Comp A) P b,
      well_formed_comp c ->
      In b (filter P (getSupport c)) ->
      well_formed_comp (Repeat c P).

(* Specifications: *)
Theorem lt_eq_false : forall n, n < n -> False.
Lemma length_nz_exists : forall (A : Type)(ls : list A), length ls > 0 -> exists a, In a ls.
Theorem getSupport_length_nz : forall (A : Set)(c : Comp A), well_formed_comp c -> length (getSupport c) > 0.
Lemma filter_NoDup : forall (A : Set)(ls : list A)(P : A -> bool), NoDup ls -> NoDup (filter P ls).
Lemma getSupport_NoDup : forall (A : Set)(c : Comp A), NoDup (getSupport c).
Lemma getSupport_Bind_In : forall (A B : Set) (c : Comp B)(f : B -> Comp A) a, In a (getSupport (Bind c f)) -> exists b, In b (getSupport c) /\ In a (getSupport (f b)).