|
|
|
|
|
Description |
A Monad Transformer for explicitly typed checked exceptions.
The exceptions thrown by a computation are inferred by the typechecker
and appear in the type signature of the computation as Throws constraints.
Exceptions are defined using the extensible exceptions framework of Marlow (documented in Control.Exception):
- An Extensible Dynamically-Typed Hierarchy of Exceptions, by Simon Marlow, in Haskell '06.
Example
data DivideByZero = DivideByZero deriving (Show, Typeable)
data SumOverflow = SumOverflow deriving (Show, Typeable)
instance Exception DivideByZero
instance Exception SumOverflow
data Expr = Add Expr Expr | Div Expr Expr | Val Double
eval (Val x) = return x
eval (Add a1 a2) = do
v1 <- eval a1
v2 <- eval a2
let sum = v1 + v2
if sum < v1 || sum < v2 then throw SumOverflow else return sum
eval (Div a1 a2) = do
v1 <- eval a1
v2 <- eval a2
if v2 == 0 then throw DivideByZero else return (v1 / v2)
GHCi infers the following types
eval :: (Throws DivideByZero l, Throws SumOverflow l) => Expr -> EM l Double
eval `catch` \ (e::DivideByZero) -> return (-1) :: Throws SumOverflow l => Expr -> EM l Double
runEM(eval `catch` \ (e::SomeException) -> return (-1))
:: Expr -> Double
|
|
Synopsis |
|
|
|
|
Important trivia
|
|
Hierarchies of Exceptions
|
|
If your sets of exceptions are hierarchical then you need to
teach Throws about the hierarchy.
-- TopException
-- |
instance Throws MidException (Caught TopException l) -- |
-- MidException
instance Throws ChildException (Caught MidException l) -- |
instance Throws ChildException (Caught TopException l) -- |
-- ChildException
|
|
Unchecked and unexplicit 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.
|
|
Unexplicit exceptions
|
|
An exception E can be made unexplicit: E will not appear in the list
of exceptions. To do so include the following instance in your code:
instance Throws E l
|
|
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 | (Monoid w, MonadRWS r w s m) => MonadRWS r w s (EMT l m) | (Monoid w, MonadRWS r w s m) => MonadRWS r w s (EMT l m) | (Exception e, Throws e l, Monad m) => MonadFailure e (EMT l m) | (Exception e, Throws e l, Monad m) => WrapFailure e (EMT l m) | MonadReader r m => MonadReader r (EMT l m) | MonadState s m => MonadState s (EMT l m) | (Monoid w, MonadWriter w m) => MonadWriter w (EMT l m) | MonadReader r m => MonadReader r (EMT l m) | MonadState s m => MonadState s (EMT l m) | (Monoid w, MonadWriter w m) => MonadWriter w (EMT l m) | (Exception e, Monad m) => MonadCatch e (EMT (Caught e l) m) (EMT l m) | Throws MonadZeroException l => MonadPlus (EM l) | Throws MonadZeroException l => MonadPlus (EM l) | MonadTrans (EMT l) | MonadTrans (EMT l) | 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) | (Throws SomeException l, MonadIO m) => MonadIO (EMT l m) | MonadCont m => MonadCont (EMT l m) | MonadCont m => MonadCont (EMT l m) | (Throws SomeException l, MonadIO m) => MonadIO (EMT l m) | (Monad m, Try m l) => Try (EMT l m) l |
|
|
|
|
|
|
Run a computation explicitly handling exceptions
|
|
|
Run a safe computation
|
|
|
Run a safe computation checking even unchecked (UncaughtException) exceptions
|
|
|
|
|
Uncaught Exceptions model 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 as unchecked too. This is a shortcoming of the current encoding.
If that is what you want, then declare E as unchecked and unexplicit
using an instance of Throws:
instance Throws E l
| | Instances | |
|
|
The Throws type class
|
|
|
Throws is a type level binary relationship
used to model a list of exceptions.
There are two cases in which the user may want
to add further instances to Throws.
1. To encode subtyping.
2. To declare an exception as unexplicit (a programming error).
- 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
SomeException is automatically
an ancestor of every other exception type.
- Programming Errors
-
In order to declare an exception E as a programming error, which should
not be explicit nor checked, use a Throws instance as follows:
instance Throws e l
| | Instances | |
|
|
|
A type level witness of a exception handler.
| Instances | |
|
|
The Try type class for absorbing other failure types
|
|
|
| Methods | | The purpose of try is to combine EMT with other failure handling data types.
try accepts a failing computation and turns it into an EMT computation.
The instances provided allow you to try on Maybe and Either computations.
|
| | Instances | |
|
|
|
Constructors | | 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 | |
|
|
Reexports
|
|
Exception (toException, fromException) |
|
SomeException (SomeException) |
|
Typeable (typeOf) |
|
MonadFailure (failure) |
|
WrapFailure (wrapFailure) |
|
MonadLoc (withLoc) |
|
withLocTH |
|
Produced by Haddock version 2.4.2 |