问题
I'm trying to use the ExceptT
monad transformer to catch any exception thrown by a function, like so:
import Control.Exception
import Control.Monad.Trans.Except
badFunction :: ExceptT SomeException IO ()
badFunction = throw DivideByZero
main :: IO ()
main = do
r <- runExceptT badFunction
case r of Left _ -> putStrLn "caught error"
Right _ -> putStrLn "nope, didn't catch no error"
... but the exception happily flies by. What am I doing wrong?
Edit: to clarify, the aim is to catch any exception thrown by a function, regardless of how the exception was thrown. If it makes any difference, the real function call is at the bottom of a fairly deep monad transformer stack. I don't mind missing things like thrown strings (bad programmer!).
回答1:
First, you catch your runtime exception. It can be done by using either monad-control
(and lifted-base
) or exceptions
. Michael Snoyman has a nice article comparing the two: Exceptions and monad transformers
Second, you embed the caught exception in ExceptT
.
Here's the complete working code:
import Control.Exception.Lifted
import Control.Monad.Trans.Except
badFunction :: ExceptT SomeException IO ()
badFunction = throw DivideByZero
intercept
:: ExceptT SomeException IO a
-> ExceptT SomeException IO a
intercept a = do
r <- try a
case r of
Right x -> return x
Left e -> throwE e
main :: IO ()
main = do
r <- runExceptT $ intercept badFunction
case r of Left _ -> putStrLn "caught error"
Right _ -> putStrLn "nope, didn't catch no error"
A more compact (but perhaps somewhat less obvious) definition of intercept
is
intercept
:: ExceptT SomeException IO a
-> ExceptT SomeException IO a
intercept = handle throwE
回答2:
I believe you want throwE
, not throw
.
Also, it'll be an ArithException
, not a SomeException
.
来源:https://stackoverflow.com/questions/26385809/catch-someexception-with-exceptt