
On Thu, Oct 14, 2010 at 4:28 PM, Antoine Latter
On Thu, Oct 14, 2010 at 7:15 AM, Michael Snoyman
wrote: By the way, here is how I would implement the ErrorT MonadCatchIO instance:
instance (MonadCatchIO m, Error e) => MonadCatchIO (ErrorT e m) where m `catch` f = mapErrorT (\m' -> m' `catch` \e -> runErrorT $ f e) m block = mapErrorT block unblock = mapErrorT unblock bracket before after thing = block $ do a <- before unblock $ thing a `finally` after a bracket_ before after thing = block $ do _ <- before unblock $ thing `finally` after finally thing after = mapErrorT (`finally` runErrorT after) thing
By using "finally" inside of the definitions of bracket, bracket_ and finally, we can ensure that if there is any "special" monad underneath our ErrorT, the cleanup function will still run.
Michael
A while back I wrote a small package built on MonadCatchIO to give the equivalent of alloca and the like[1].
I haven't used it much because I couldn't convince myself that the resources would eventually be freed in a monad with non-standard control flow (such as the continuation based iteratee-0.4[2]).
I think proper exception control in monad transformer stacks is something too important to simply give up on. It seems to me that the MonadCatchIO family is broken, and that the maintainer isn't interested in fixing it. Given that, perhaps we need to design a new approach that works properly and is thoroughly tested, and perhaps deprecate the MonadCatchIO family of packages so as not to leave a stumbling block for people trying to do proper exception handling. Did you have particular reasons why you thought the resources would not be freed correctly Antoine? I'd love any insight you have on this. Michael