I need help to understand the usage of the three Haskell functions
- try (
Control.Exception.try :: Exception e => IO a -> IO (Either e a)) - catch (
Control.Exception.catch :: Exception e => IO a -> (e -> IO a) -> IO a) - handle (
Control.Exception.handle :: Exception e => (e -> IO a) -> IO a -> IO a)
I need to know several things:
- When do I use which function?
- How do I use this function with some simple example?
- Where is the difference between catch and handle? They have nearly the same signature only with a different order.
I will try to write down my trials and hope you can help me:
try
I have an example like:
x = 5 `div` 0
test = try (print x) :: IO (Either SomeException ())
I have two questions:
-
How can I set a custom error output?
-
What can i do to set all errors to SomeException so I dont must write the
:: IO (Either SomeException())
catch/try
Can you show me a short example with a custom error output?
When do I use which function?
Here’s the recommendation from the Control.Exception documentation:
finally,bracketoronException.tryfamily.catchorcatchJust.try :: Exception e => IO a -> IO (Either e a)
trytakes anIOaction to run, and returns anEither. If the computation succeeded, the result is given wrapped in aRightconstructor. (Think right as opposed to wrong). If the action threw an exception of the specified type, it is returned in aLeftconstructor. If the exception was not of the appropriate type, it continues to propagate up the stack. SpecifyingSomeExceptionas the type will catch all exceptions, which may or may not be a good idea.Note that if you want to catch an exception from a pure computation, you will have to use
evaluateto force evaluation within thetry.catch :: Exception e => IO a -> (e -> IO a) -> IO a
catchis similar totry. It first tries to run the specifiedIOaction, but if an exception is thrown the handler is given the exception to get an alternative answer.However, there is one important difference. When using
catchyour handler cannot be interrupted by an asynchroneous exception (i.e. thrown from another thread viathrowTo). Attempts to raise an asynchroneous exception will block until your handler has finished running.Note that there is a different
catchin the Prelude, so you might want to doimport Prelude hiding (catch).handle :: Exception e => (e -> IO a) -> IO a -> IO a
handleis simplycatchwith the arguments in the reversed order. Which one to use depends on what makes your code more readable, or which one fits better if you want to use partial application. They are otherwise identical.tryJust, catchJust and handleJust
Note that
try,catchandhandlewill catch all exceptions of the specified/inferred type.tryJustand friends allow you to specify a selector function which filters out which exceptions you specifically want to handle. For example, all arithmetic errors are of typeArithException. If you only want to catchDivideByZero, you can do:A note on purity
Note that this type of exception handling can only happen in impure code (i.e. the
IOmonad). If you need to handle errors in pure code, you should look into returning values usingMaybeorEitherinstead (or some other algebraic datatype). This is often preferable as it’s more explicit so you always know what can happen where. Monads likeControl.Monad.Errormakes this type of error handling easier to work with.See also: