I'm trying to write a function that drops a list of tables from a database (e.g., tables A, B and C).
This function has the following type, it returns a list of booleans indicating whether each table was successfully dropped:

dropTables :: (IConnection conn) => conn -> [String] -> IO [Bool]

Now, imagine table C depends on table B, i.e., table B cannot be dropped while table C exists. The function will be able to drop tables A and C, but not B, and so it will return [True, False, True].

So, I wanted to write a function that takes a list of tables, and calls dropTables. If any of the operations fail, it calls dropTables again but this time only with the tables that could not be dropped in the first iteration. And so on, until either all tables have been dropped, or progression halts (i.e. all operations in a given iteration fail, due to e.g. a connection being closed)

I was wondering if there's a simpler way of implementing repeatUntilAll.

I had a look around Control.Monad.Loops to see if there was anything I could use, but no such luck. Being a Haskell novice doesn't help either, I'm only familiar with a very small part of the core libraries.

Other improvements (naming, conventions, greater generalization) are also welcome.

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:

(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.