Repeat an action for a set of elements until all succeed, or progression halts
I quite like your aim for simplifying the function and factoring out the generic part. One solution (untested, just compiled) could be done using iterateUntilM from Control.Monad.Loops:

repeatUntilAll :: (Monad m) =&gt; ([a] -&gt; m [Bool]) -&gt; [a] -&gt; m [a]
repeatUntilAll f = fmap snd . iterateUntilM fst step . ((,) True)
  where
    step (_, xs) = do
        results &lt;- f xs
        let ys = map fst $ filter (not . snd) $ zip xs results
        return (length xs &gt; length ys, ys)


We pass an additional boolean flag that tells if a particular step was an improvement or not. Note that we don't need to check for the final condition - if everything succeeds, there will be one final step with an empty list and then we'll stop.

However, I like a bit more yet another solution. Notice this: Let's say the first removal succeeds, the second fails and because of this, everything else. Then we iterate through the whole list, and then once more, before we finish. But in fact we know that we're bound to fail when we fail to remove all the other elements. In this second solution, we loop over all elements without distinguishing a full pass. Instead we "reset" the state every time we succeed and try all the failed elements again. I also like its simplicity, compared to the previous one:

-- | Tries to repeatedly act on each element until the action succeeds on each.
-- Alternatively stops when the action fails for all unfinished elements in one full round.
tryOnAll :: (Monad m) =&gt; (a -&gt; m Bool) -&gt; [a] -&gt; m [a]
tryOnAll f = loop []
  where
    loop fs [] = return fs
    loop fs (w : ws) = do
        r &lt;- f w
        if r then loop [] (fs ++ ws)
             else loop (w : fs) ws


(Again compiled but untested.) Note that in fs ++ ws we change the order of elements. This shouldn't be a problem, as we need to try out all before we fail anyway, but if you don't like it, you can use Seq instead of [] and maintain sequential order. Or you could also replace it with ws ++ reverse fs, but only if the total number of elements is moderate, otherwise you could start having problems with its O(n) complexity.



A tiny nit, unrelated to the main problem: Haddock comments allow you to generate nice documentation.