On Fri, Oct 15, 2010 at 9:35 AM,  <o...@okmij.org> wrote:
>
> 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.
>

Perhaps I'm misunderstanding your code, but it seems like it's not
really respecting the ErrorT monad at all. Instead, it's converting
the error type to a runtime exception, which often times is not at all
what we want. A pertinent example: in Yesod, I use a modified ErrorT
to allow short-circuiting handler functions to perform special
responses such as redirects. Using your code, I believe that such code
on my part would result in a 500 server error every time, quite the
opposite of what I wanted.

I would prefer if the test read as:

> test33 = fmap (== Left "throwError") $ test3c (throwError "throwError" :: 
> ErrorT String IO String)

Which never in fact returns True. Or, more to the point, the test is
never even called, since the runtime exception prevents it.

Michael
_______________________________________________
Haskell-Cafe mailing list
Haskell-Cafe@haskell.org
http://www.haskell.org/mailman/listinfo/haskell-cafe

Reply via email to