
Michael Snoyman wrote:
I have a recommendation of how to fix this: the MonadCatchIO typeclass should be extended to include finally, onException and everything else. We can provide default definitions which will work for most monads, and short-circuiting monads like ErrorT (and I imagine ContT as well) will need to override them.
It seems that `finally' can be fixed without all these proposed additions. The method catch is the only necessary method of the class. The subject of catching errors in non-IO monads has a long history, some of which is documented at http://okmij.org/ftp/Haskell/index.html#catch-MonadIO The page points out to an old CaughtMonadIO file. I have just updated it for new Exceptions, and added the final test:
test3c go = runErrorT $ go `gfinally` (liftIO $ putStrLn "sequel called")
test31 = test3c (return "return" :: ErrorT String IO String)
*CaughtMonadIO> test31 sequel called Right "return"
test32 = test3c (error "error" :: ErrorT String IO String)
*CaughtMonadIO> test32 sequel called *** Exception: error
test33 = test3c (throwError "throwError" :: ErrorT String IO String)
*CaughtMonadIO> test33 sequel called *** Exception: ErrorException "\"throwError\"" As we can see, sequel is always called. Here is the updated file: http://okmij.org/ftp/Haskell/CaughtMonadIO.lhs Incidentally, one should be very careful of using `finally' with the continuation monad. The Cont monad lets us ``enter the room once, and exit many times''. So, finally may be called more than once. We need the ugly dynamic-wind -- or try to use less powerful monads if they suffice.