Section mon_det. (* For variable discharging. *)
Variables (M: Monad) (T: Set).
Definition filter (c: T -> M bool) (l: list T): M { l': list T | length l' <= length l }.
(* Something with result type  M (list T)  is not good enough, because then   refine (u <- filter ... ; _)   just gives   u: list T, which is useless. *)
Proof with auto with arith.
induction l.
refine (ret (exist _ nil _))...
refine (
b <- c a ;
t <- IHl ;
ret (if b then exist _ (a :: proj1_sig t) _ else exist _ (proj1_sig t) _)
); simpl; destruct t...
Defined.
Proof with auto. (* todo: rename *)
induction l.
simpl. intros.
repeat rewrite mon_lunit.
rewrite H.
unfold compose...
intros.
simpl.
repeat rewrite mon_assoc.
apply e. intro.
repeat rewrite mon_assoc.
apply IHl.
intro. unfold compose.
repeat rewrite mon_lunit.
rewrite H.
unfold compose.
destruct x...
Qed.
Fixpoint simple_filter (c: T -> M bool) (l: list T): M (list T) :=
match l with
| nil => ret nil
| h :: t =>
t' <- simple_filter c t ;
b <- c h ;
ret (if b then h :: t' else t')
end.
Definition fold_filter (c: T -> M bool): list T -> M (list T) :=
foldrM (fun x l => b <- c x ; ret (if b then x :: l else l)) nil.

Lemma simple_fold_filter: forall c l, simple_filter c l = fold_filter c l.