
On Sun, Oct 17, 2010 at 1:04 PM, Arie Peterson
On Thu, 14 Oct 2010 12:01:59 +0200, Michael Snoyman
wrote: [...] which I believe is a flawed design in the MonadCatchIO-transformers package. Here are my thoughts on this and what I think needs to be done to fix it.
[...]
Try running the code with each version of go uncommented. In the first two, "sequel called" gets printed. However, in the third, it does not. The reason is short-circuiting: if we remember from the definition of finally, there are two cases we account for. If an exception is called, catch addresses it. If not, we assume that the next line will be called. However, in the presence of short-circuiting monads like ErrorT, that line of code will never get called!
Yes. That is the behaviour I would expect.
There are two kinds of exceptional values in, for instance, 'ErrorT e IO a': • IO exceptions, in the "underlying monad" 'IO'; • error values of type 'e', in the monad transformer 'ErrorT e'. The MonadCatchIO instance for ErrorT deals with the first kind only. Catching IO exceptions, and cleaning up after them, is what MonadCatchIO was invented for. I feel that I should not decide for all users how these two layers of exceptions should interact; keeping the MonadCatchIO instance oblivious to the underlying monad as much as possible seems like the safest/most general thing to do.
Meanwhile, I can see why you would want 'finally' to also catch the ErrorT errors, in your example, and circumvent the short-circuiting. However, I'm not convinced that this is always the right (expected, most useful, ...) behaviour. Maybe I just need more convincing :-).
I think the big thing I would look for is that the second argument to 'finally' always run (barring calls to System.Exit or the universe ending or whatever). Otherwise I wouldn't expect any other interaction with the 'Left' half of ErrorT. For example I wouldn't expect the 'error' half of 'try' to be run on Left, but I would expect the cleanup tasks in 'bracket' to be executed. Otherwise the function just isn't useful. Antoine