|
|
|
|
|
|
Synopsis |
|
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 {} | | 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 | | | | | class Typeable a where | | | class Try f where | | | data NothingException = NothingException | | class Failure e f where | | | class (Monad f, Applicative f, Failure e f) => MonadFailure e f | | class Failure e f => WrapFailure e f where | | | 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
|
|
|
A monad of explicitly typed, checked exceptions
|
|
|
Run a computation explicitly handling exceptions
|
|
|
Run a safe computation
|
|
|
Run a computation checking even unchecked (UncaughtExceptions) exceptions
|
|
The EMT monad transformer
|
|
|
A Monad Transformer for explicitly typed checked exceptions.
| Constructors | | Instances | |
|
|
|
|
|
Run a computation explicitly handling exceptions
|
|
|
Run a safe computation
|
|
|
Run a safe computation checking even unchecked (UncaughtException) exceptions
|
|
|
Instances | |
|
|
|
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
|
|
|
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 that MyFileNotFoundException is
a subexception of MyIOException :
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 | |
|
|
|
A type level witness of a exception handler.
| Instances | |
|
|
Exception primitives
|
|
|
The throw primitive
|
|
|
Rethrow an exception keeping the call trace
|
|
|
The catch primitive
|
|
|
Like catch but makes the call trace available
|
|
|
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.
|
|
|
Like finally, but performs the second computation only when the first one
rises an exception
|
|
|
:: Monad m | | => EMT l m a | acquire resource
| -> a -> EMT l m b | release resource
| -> a -> EMT l m c | computation
| -> EMT l m c | |
|
|
|
Capture an exception e, wrap it, and rethrow.
Keeps the original monadic call trace.
|
|
|
|
|
FailException is thrown by Monad fail
| Constructors | | Instances | |
|
|
data MonadZeroException | Source |
|
MonadZeroException is thrown by MonadPlus mzero
| Constructors | | Instances | |
|
|
|
This function may be used as a value for mplus in MonadPlus
|
|
Reexports
|
|
|
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 MismatchedParentheses catch e -> putStrLn ("Caught " ++ show (e :: MismatchedParentheses))
Caught MismatchedParentheses
*Main> throw MismatchedParentheses catch e -> putStrLn ("Caught " ++ show (e :: SomeFrontendException))
Caught MismatchedParentheses
*Main> throw MismatchedParentheses catch e -> putStrLn ("Caught " ++ show (e :: SomeCompilerException))
Caught MismatchedParentheses
*Main> throw MismatchedParentheses catch e -> putStrLn ("Caught " ++ show (e :: IOException))
*** Exception: MismatchedParentheses
| | Methods | | | Instances | |
|
|
data SomeException where | Source |
|
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 | | Instances | |
|
|
|
The class Typeable allows a concrete representation of a type to
be calculated.
| | Methods | | Takes a value of type a and returns a concrete representation
of that type. The value of the argument should be ignored by
any instance of Typeable, so that it is safe to pass undefined as
the argument.
|
| | Instances | |
|
|
|
| Associated Types | | | Methods | | | Instances | |
|
|
|
Constructors | | Instances | |
|
|
|
| Methods | | | Instances | |
|
|
|
| Instances | |
|
|
|
| Methods | | 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 | |
|
|
|
Generating stack traces for failures
| | Methods | | withLoc records the given source location in the failure trace
if the underlying monad supports recording location traces
|
| | Instances | |
|
|
|
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
|
|
Produced by Haddock version 2.6.1 |