Control.Monad.Exception
Contents
- type EM l = EMT l Identity
- tryEM :: EM AnyException a -> Either SomeException a
- runEM :: EM NoExceptions a -> a
- runEMParanoid :: EM ParanoidMode a -> a
- newtype EMT l m a = EMT {
- unEMT :: m (Either (CallTrace, CheckedException l) a)
- type CallTrace = [String]
- tryEMT :: Monad m => EMT AnyException m a -> m (Either SomeException a)
- runEMT :: Monad m => EMT NoExceptions m a -> m a
- runEMTParanoid :: Monad m => EMT ParanoidMode m a -> m a
- data AnyException
- class Exception e => UncaughtException e
- class Exception e => Throws e l
- data Caught e l
- throw :: (Exception e, Throws e l, Monad m) => e -> EMT l m a
- rethrow :: (Throws e l, Monad m) => CallTrace -> e -> EMT l m a
- catch :: (Exception e, Monad m) => EMT (Caught e l) m a -> (e -> EMT l m a) -> EMT l m a
- catchWithSrcLoc :: (Exception e, Monad m) => EMT (Caught e l) m a -> (CallTrace -> e -> EMT l m a) -> EMT l m a
- finally :: Monad m => EMT l m a -> EMT l m b -> EMT l m a
- onException :: Monad m => EMT l m a -> EMT l m b -> EMT l m a
- bracket :: Monad m => EMT l m a -> (a -> EMT l m b) -> (a -> EMT l m c) -> EMT l m c
- wrapException :: (Exception e, Throws e' l, Monad m) => (e -> e') -> EMT (Caught e l) m a -> EMT l m a
- showExceptionWithTrace :: Exception e => [String] -> e -> String
- data FailException = FailException String
- data MonadZeroException = MonadZeroException
- mplusDefault :: Monad m => EMT l m a -> EMT l m a -> EMT l m a
- class (Typeable e, Show e) => Exception e where
- toException :: e -> SomeException
- fromException :: SomeException -> Maybe e
- data SomeException where
- SomeException :: Exception e => e -> SomeException
- class Typeable a where
- class Try f where
- data NothingException = NothingException
- class Monad f => Failure e f where
- failure :: e -> f v
- class Failure e f => WrapFailure e f where
- wrapFailure :: (forall eIn. Exception eIn => eIn -> e) -> f a -> f a
- class Monad m => MonadLoc m where
- withLocTH :: Q Exp
Important trivia
Hierarchies of Exceptions
If your sets of exceptions are hierarchical then you need to
teach Throws
about the hierarchy. See the documentation of
Throws
for more info.
Unchecked exceptions
Unchecked exceptions
An exception E
can be declared as unchecked by making E
an instance of
UncaughtException
.
instance UncaughtException E
E
will still appear in the list of exceptions thrown
by a computation but runEMT
will not complain if E
escapes the computation
being run.
Also, tryEMT
allows you to run a computation regardless of the exceptions it throws.
Stack Traces
Stack traces are provided via the MonadLoc package. All you need to do is add the following pragma at the top of your Haskell source files and use do-notation:
{ # OPTIONS_GHC -F -pgmF MonadLoc # }
Only statements in do blocks appear in the stack trace.
Example:
f () = do throw MyException g a = do f a main = runEMT $ do g () `catchWithSrcLoc` \loc (e::MyException) -> lift(putStrLn$ showExceptionWithTrace loc e)
-- Running main produces the output:
*Main> main MyException in f, Main(example.hs): (1,6) g, Main(example.hs): (2,6) main, Main(example.hs): (5,9) main, Main(example.hs): (4,16)
Understanding GHC errors
A type error of the form:
No instance for (UncaughtException MyException) arising from a use of `g' at examples/docatch.hs:21:32-35 Possible fix: add an instance declaration for (UncaughtException MyException) In the expression: g ()
is the type checker saying:
"hey, you are trying to run a computation which throws a MyException
without handling it, and I won't let you"
Either handle it or declare MyException
as an UncaughtException
.
A type error of the form:
Overlapping instances for Throws MyException (Caught e NoExceptions) arising from a use of `g' at docatch.hs:24:3-6 Matching instances: instance (Throws e l) => Throws e (Caught e' l) -- Defined at ../Control/Monad/Exception/Throws.hs:46:9-45 instance (Exception e) => Throws e (Caught e l) -- Defined at ../Control/Monad/Exception/Throws.hs:47:9-44 (The choice depends on the instantiation of `e' ...
is due to an exception handler for MyException
missing a type annotation to pin down the type of the exception.
The EM monad
tryEM :: EM AnyException a -> Either SomeException aSource
Run a computation explicitly handling exceptions
runEM :: EM NoExceptions a -> aSource
Run a safe computation
runEMParanoid :: EM ParanoidMode a -> aSource
Run a computation checking even unchecked (UncaughtExceptions
) exceptions
The EMT monad transformer
A Monad Transformer for explicitly typed checked exceptions.
Constructors
EMT | |
Fields
|
Instances
(Exception e, Throws e l, Failure e m, Monad m) => WrapFailure e (EMT l m) | |
(Exception e, Throws e l, Monad m) => Failure e (EMT l m) | |
(Exception e, Monad m) => MonadCatch e (EMT (Caught e l) m) (EMT l m) | |
Monad m => Monad (EMT l m) | |
Monad m => Functor (EMT l m) | |
MonadFix m => MonadFix (EMT l m) | |
Monad m => Applicative (EMT l m) | |
Monad m => MonadLoc (EMT l m) |
tryEMT :: Monad m => EMT AnyException m a -> m (Either SomeException a)Source
Run a computation explicitly handling exceptions
runEMT :: Monad m => EMT NoExceptions m a -> m aSource
Run a safe computation
runEMTParanoid :: Monad m => EMT ParanoidMode m a -> m aSource
Run a safe computation checking even unchecked (UncaughtException
) exceptions
data AnyException Source
Instances
Exception e => Throws e AnyException |
class Exception e => UncaughtException e Source
UncaughtException models unchecked exceptions
In order to declare an unchecked exception E
,
all that is needed is to make e
an instance of UncaughtException
instance UncaughtException E
Note that declaring an exception E as unchecked does not automatically turn its children unchecked too. This is a shortcoming of the current encoding.
Instances
The Throws type class
class Exception e => Throws e l Source
Throws
is a type level binary relationship
used to model a list of exceptions.
There is only one case in which the user must
add further instances to Throws
.
If your sets of exceptions are hierarchical then you need to
teach Throws
about the hierarchy.
- Subtyping
-
As there is no way to automatically infer
the subcases of an exception, they have to be encoded
manually mirroring the hierarchy defined in the defined
Exception
instances. For example, the following instance encodes thatMyFileNotFoundException
is a subexception ofMyIOException
:
instance Throws MyFileNotFoundException (Caught MyIOException l)
Throws
is not a transitive relation and every ancestor relation
must be explicitly encoded.
-- TopException -- | instance Throws MidException (Caught TopException l) -- | -- MidException instance Throws ChildException (Caught MidException l) -- | instance Throws ChildException (Caught TopException l) -- | -- ChildException
Note that SomeException
is automatically an ancestor of every other exception type.
Instances
UncaughtException e => Throws e NoExceptions | |
Exception e => Throws e AnyException | |
Exception e => Throws e (Caught SomeException l) |
|
Exception e => Throws e (Caught e l) | |
Throws e l => Throws e (Caught e' l) | |
Throws SomeException (Caught SomeException l) | |
Throws TailFailure (Caught SafeException l) | |
Throws InitFailure (Caught SafeException l) | |
Throws HeadFailure (Caught SafeException l) | |
Throws LastFailure (Caught SafeException l) | |
Throws MinimumFailure (Caught SafeException l) | |
Throws MaximumFailure (Caught SafeException l) | |
Throws Foldr1Failure (Caught SafeException l) | |
Throws Foldl1Failure (Caught SafeException l) | |
Throws FromJustFailure (Caught SafeException l) | |
Throws IndexFailure (Caught SafeException l) | |
Throws ReadFailure (Caught SafeException l) | |
(Typeable a, Show a) => Throws (LookupFailure a) (Caught SafeException l) |
A type level witness of a exception handler.
Instances
Exception e => Throws e (Caught SomeException l) |
|
Exception e => Throws e (Caught e l) | |
Throws e l => Throws e (Caught e' l) | |
Throws SomeException (Caught SomeException l) | |
Throws TailFailure (Caught SafeException l) | |
Throws InitFailure (Caught SafeException l) | |
Throws HeadFailure (Caught SafeException l) | |
Throws LastFailure (Caught SafeException l) | |
Throws MinimumFailure (Caught SafeException l) | |
Throws MaximumFailure (Caught SafeException l) | |
Throws Foldr1Failure (Caught SafeException l) | |
Throws Foldl1Failure (Caught SafeException l) | |
Throws FromJustFailure (Caught SafeException l) | |
Throws IndexFailure (Caught SafeException l) | |
Throws ReadFailure (Caught SafeException l) | |
(Exception e, Monad m) => MonadCatch e (EMT (Caught e l) m) (EMT l m) | |
(Typeable a, Show a) => Throws (LookupFailure a) (Caught SafeException l) |
Exception primitives
rethrow :: (Throws e l, Monad m) => CallTrace -> e -> EMT l m aSource
Rethrow an exception keeping the call trace
catch :: (Exception e, Monad m) => EMT (Caught e l) m a -> (e -> EMT l m a) -> EMT l m aSource
The catch primitive
catchWithSrcLoc :: (Exception e, Monad m) => EMT (Caught e l) m a -> (CallTrace -> e -> EMT l m a) -> EMT l m aSource
Like catch
but makes the call trace available
finally :: Monad m => EMT l m a -> EMT l m b -> EMT l m aSource
Sequence two computations discarding the result of the second one. If the first computation rises an exception, the second computation is run and then the exception is rethrown.
onException :: Monad m => EMT l m a -> EMT l m b -> EMT l m aSource
Like finally, but performs the second computation only when the first one rises an exception
wrapException :: (Exception e, Throws e' l, Monad m) => (e -> e') -> EMT (Caught e l) m a -> EMT l m aSource
Capture an exception e, wrap it, and rethrow. Keeps the original monadic call trace.
showExceptionWithTrace :: Exception e => [String] -> e -> StringSource
data MonadZeroException Source
MonadZeroException
is thrown by MonadPlus mzero
Constructors
MonadZeroException |
Reexports
class (Typeable e, Show e) => Exception e where
Any type that you wish to throw or catch as an exception must be an
instance of the Exception
class. The simplest case is a new exception
type directly below the root:
data MyException = ThisException | ThatException deriving (Show, Typeable) instance Exception MyException
The default method definitions in the Exception
class do what we need
in this case. You can now throw and catch ThisException
and
ThatException
as exceptions:
*Main> throw ThisException catch
e -> putStrLn ("Caught " ++ show (e :: MyException))
Caught ThisException
In more complicated examples, you may wish to define a whole hierarchy of exceptions:
--------------------------------------------------------------------- -- Make the root exception type for all the exceptions in a compiler data SomeCompilerException = forall e . Exception e => SomeCompilerException e deriving Typeable instance Show SomeCompilerException where show (SomeCompilerException e) = show e instance Exception SomeCompilerException compilerExceptionToException :: Exception e => e -> SomeException compilerExceptionToException = toException . SomeCompilerException compilerExceptionFromException :: Exception e => SomeException -> Maybe e compilerExceptionFromException x = do SomeCompilerException a <- fromException x cast a --------------------------------------------------------------------- -- Make a subhierarchy for exceptions in the frontend of the compiler data SomeFrontendException = forall e . Exception e => SomeFrontendException e deriving Typeable instance Show SomeFrontendException where show (SomeFrontendException e) = show e instance Exception SomeFrontendException where toException = compilerExceptionToException fromException = compilerExceptionFromException frontendExceptionToException :: Exception e => e -> SomeException frontendExceptionToException = toException . SomeFrontendException frontendExceptionFromException :: Exception e => SomeException -> Maybe e frontendExceptionFromException x = do SomeFrontendException a <- fromException x cast a --------------------------------------------------------------------- -- Make an exception type for a particular frontend compiler exception data MismatchedParentheses = MismatchedParentheses deriving (Typeable, Show) instance Exception MismatchedParentheses where toException = frontendExceptionToException fromException = frontendExceptionFromException
We can now catch a MismatchedParentheses
exception as
MismatchedParentheses
, SomeFrontendException
or
SomeCompilerException
, but not other types, e.g. IOException
:
*Main> throw MismatchedParenthesescatch
e -> putStrLn ("Caught " ++ show (e :: MismatchedParentheses)) Caught MismatchedParentheses *Main> throw MismatchedParenthesescatch
e -> putStrLn ("Caught " ++ show (e :: SomeFrontendException)) Caught MismatchedParentheses *Main> throw MismatchedParenthesescatch
e -> putStrLn ("Caught " ++ show (e :: SomeCompilerException)) Caught MismatchedParentheses *Main> throw MismatchedParenthesescatch
e -> putStrLn ("Caught " ++ show (e :: IOException)) *** Exception: MismatchedParentheses
Instances
data SomeException where
The SomeException
type is the root of the exception type hierarchy.
When an exception of type e
is thrown, behind the scenes it is
encapsulated in a SomeException
.
Constructors
SomeException :: Exception e => e -> SomeException |
Instances
Show SomeException | |
Typeable SomeException | |
Exception SomeException | |
UncaughtException SomeException | |
Exception e => Throws e (Caught SomeException l) |
|
Throws SomeException (Caught SomeException l) |
class Typeable a where
The class Typeable
allows a concrete representation of a type to
be calculated.
Methods
Instances
data NothingException
Constructors
NothingException |
class Failure e f => WrapFailure e f where
Methods
wrapFailure :: (forall eIn. Exception eIn => eIn -> e) -> f a -> f a
Wrap the failure value, if any, with the given function. This is useful in particular when you want all the exceptions returned from a certain library to be of a certain type, even if they were generated by a different library.
Instances
Exception e => WrapFailure e IO | |
(Exception e, Throws e l, Failure e m, Monad m) => WrapFailure e (EMT l m) |
class Monad m => MonadLoc m where
Generating stack traces for failures
withLocTH
is a convenient TH macro which expands to withLoc
<source location>
It should only be used when the MonadLoc preprocessor is not available.
Usage:
f x = $withLocTH $ do $withLocTH $ something x < -$withLocTH $ something-else ...
NOTE: unfortunately type signatures are necessary when using withLocTH