On Sun, Oct 17, 2010 at 8:04 PM, Arie Peterson <[email protected]> wrote: > On Thu, 14 Oct 2010 12:01:59 +0200, Michael Snoyman > <[email protected]> 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 can't think of a single use case where the current behavior is desired. On the other hand, many common cases would require the semantics I'm looking for: * My use case: returning a resource to a resource pool upon completion of an action. * Freeing allocated memory (probably better to use bracket there, but the same issue exists for that function). * Closing a file handle at the end of an action (again, a good use case for bracket). While we're on the topic, I also found a problem with the ContT instance of MonadCatchIO which resulted in double-freeing of memory[1]. I understand from Oleg's comments earlier in this thread that this is an expected behavior of the ContT monad, but I *don't* think it's an expected behavior of the bracket_ function. If there's no way to define a MonadCatchIO instance of ContT that only calls the cleanup code once, perhaps it doesn't make sense to define that instance at all. > By the way: my apologies for not being more responsive and proactive in > this matter. At the moment, I have very little time for my haskell > endeavours. But more importantly, my maintainership of > MonadCatchIO-transformers is mostly coincidental. (I found the > MonadCatchIO-mtl code very useful, except I needed it for 'transformers' > instead of 'mtl'. So, I forked it (at that time, only the cabal file > needed editing), and put it on hackage.) I hadn't realized that you weren't the maintainer of MonadCatchIO-mtl (I simply never looked). I've CCed him on this issue as well. > If you feel that as maintainer I'm more of a roadblock than helping you > make effective use of this library, then perhaps you should take over > maintainership. Thank you for the offer, but I don't think I'm in a position to take over maintainership of another library. However, I think that my original suggestion of moving all of the exception-handling functions into the type class itself would solve the current issue; is there a reason not to do so? I'm still not sure what to do about ContT. Michael [1] http://www.mail-archive.com/[email protected]/msg77183.html _______________________________________________ Haskell-Cafe mailing list [email protected] http://www.haskell.org/mailman/listinfo/haskell-cafe
