control-monad-exception-0.6: Explicitly typed, checked exceptions with stack tracesSource codeContentsIndex
Control.Monad.Exception
Contents
Important trivia
Hierarchies of Exceptions
Unchecked and unexplicit exceptions
Unchecked exceptions
Unexplicit exceptions
Stack Traces
Understanding GHC errors
The EM monad
The EMT monad transformer
The Throws type class
The Try type class for absorbing other failure types
Exception primitives
Reexports
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
type EM l = EMT l Identity
tryEM :: EM (AnyException l) 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 l) m a -> m (Either SomeException a)
runEMT :: Monad m => EMT NoExceptions m a -> m a
runEMTParanoid :: Monad m => EMT ParanoidMode m a -> m a
type AnyException = Caught SomeException
class Exception e => UncaughtException e
class Exception e => Throws e l
data Caught e l
class Try m l where
try :: Monad m' => m a -> EMT l m' a
data NothingException = NothingException
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
Exception (toException, fromException)
SomeException (SomeException)
Typeable (typeOf)
MonadFailure (failure)
WrapFailure (wrapFailure)
MonadLoc (withLoc)
withLocTH
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
type EM l = EMT l IdentitySource
A monad of explicitly typed, checked exceptions
tryEM :: EM (AnyException l) 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
newtype EMT l m a Source
A Monad Transformer for explicitly typed checked exceptions.
Constructors
EMT
unEMT :: m (Either (CallTrace, CheckedException l) a)
show/hide 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
type CallTrace = [String]Source
tryEMT :: Monad m => EMT (AnyException l) 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
type AnyException = Caught SomeExceptionSource
class Exception e => UncaughtException e Source

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
show/hide 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 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
show/hide Instances
data Caught e l Source
A type level witness of a exception handler.
show/hide Instances
The Try type class for absorbing other failure types
class Try m l whereSource
Methods
try :: Monad m' => m a -> EMT l m' aSource
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.
show/hide Instances
Throws NothingException l => Try Maybe l
(Exception e, Throws e l) => Try (Either e) l
(Monad m, Try m l) => Try (EMT l m) l
data NothingException Source
Constructors
NothingException
show/hide Instances
Exception primitives
throw :: (Exception e, Throws e l, Monad m) => e -> EMT l m aSource
The throw primitive
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
bracketSource
:: Monad m
=> EMT l m aacquire resource
-> a -> EMT l m brelease resource
-> a -> EMT l m ccomputation
-> EMT l m c
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 FailException Source
FailException is thrown by Monad fail
Constructors
FailException String
show/hide Instances
data MonadZeroException Source
MonadZeroException is thrown by MonadPlus mzero
Constructors
MonadZeroException
show/hide Instances
Reexports
Exception (toException, fromException)
SomeException (SomeException)
Typeable (typeOf)
MonadFailure (failure)
WrapFailure (wrapFailure)
MonadLoc (withLoc)
withLocTH
Produced by Haddock version 2.4.2