# LANGUAGE CPP #

| 
 A monad transformer for explicitly typed checked exceptions with support for asynchronous exception handling . Explicit exceptions are supported by the ideas described in : 

   *   , \"Explicitly Typed Exceptions for Haskell\ " , 
     PADL'10 , January 2010 , < -Typed-Exceptions-for-Haskell-PADL-10 > 

 The exceptions thrown by a computation are inferred by the typechecker 
 and appear in the type signature of the computation as ' Throws ' constraints . 

 Support for asynchronous exceptions is provided by the monad - control package . 

   /Example/ 

   > data DivideByZero = DivideByZero deriving ( Show ,  ) 
   > data SumOverflow   = SumOverflow   deriving ( Show ,  ) 
  
   > instance Exception DivideByZero 
   > instance Exception SumOverflow 
  
   > data Expr = Add   |    |   

   > eval (   )      = 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  else return ( v1 / v2 ) 

   GHCi infers the following types 
  
   > eval                                              : : ( Throws  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 

A monad transformer for explicitly typed checked exceptions with support for asynchronous exception handling. Explicit exceptions are supported by the ideas described in:

  * Jose Iborra, \"Explicitly Typed Exceptions for Haskell\",
    PADL'10, January 2010, <-Typed-Exceptions-for-Haskell-PADL-10>

The exceptions thrown by a computation are inferred by the typechecker
and appear in the type signature of the computation as 'Throws' constraints.

Support for asynchronous exceptions is provided by the monad-control package.

  /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
-}

module Control.Monad.Exception.IO (
-- * Important trivia
-- ** Hierarchies of Exceptions
-- $hierarchies

-- ** Unchecked exceptions
-- *** Unchecked exceptions
-- $unchecked

-- ** Stack Traces
-- $stacktraces

  * * Understanding GHC errors
-- $errors

-- * The EM monad
    EM,  tryEM, tryEMWithLoc, runEM, runEMParanoid,

-- * The EMT monad transformer
    EMT(..), CallTrace, tryEMT, tryEMTWithLoc, runEMT, runEMTParanoid, AnyException, UncaughtException,

-- ** The Throws type class
   Throws, Caught,

-- * Exception primitives
      throw, rethrow, catch, catchWithSrcLoc,
    finally, onException, bracket, wrapException,

    showExceptionWithTrace,
    FailException(..), MonadZeroException(..), mplusDefault,

  * 
    Exception(..), SomeException(..), Typeable,
    Failure(..),
#if !MIN_VERSION_failure(0,2,0)
    Try(..), NothingException(..),
    WrapFailure(..),
#endif
) where

import Control.Monad.Exception.Base
import Control.Monad.Exception.Throws
import Control.Monad.Exception.Catch (Exception, SomeException, fromException, MonadCatch)
import qualified Control.Monad.Exception.Catch
import Control.Failure
import Control.Monad.Trans.Control
import Data.Typeable
import Control.Exception.Lifted as CE (try)

{- $hierarchies
 If exceptions are hierarchical then you need to
   teach 'Throws' about the hierarchy. See the documentation of
   'Throws' for more info.
-}
  $ unchecked 
 An exception  can be declared as unchecked by making  an instance of 
    ' UncaughtException ' . 

 > instance UncaughtException E 

     will still appear in the list of exceptions thrown 
    by a computation but '  ' will not complain if  escapes the computation 
    being run . 

 Also , ' tryEMT ' allows you to run a computation regardless of the exceptions it throws . 

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.
-}


  $ stacktraces 
  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  
 >        g a   = do f a 
 > 
 >        main = runEMT $ do 
 >                 g ( ) ` catchWithSrcLoc ` 
 >                         \loc ( e::MyException ) - > lift(putStrLn$ showExceptionWithTrace  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 ) 


 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)

-}


  $ 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 :  ( ) 

 is the type checker saying : 

 \"hey , you are trying to run a computation which throws a @MyException@ without handling it , and I wo n'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 . 

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 catch primitive
catch :: (Exception e, MonadBaseControl IO m) => EMT (Caught e l) m a -> (e -> EMT l m a) -> EMT l m a
catch emt h = catchWithSrcLoc emt (const h)

unwrap :: MonadBaseControl IO m => EMT l m a -> m (Either (CallTrace, CheckedException l) a)
unwrap m = do
  v <- CE.try $ unEMT m
  case v of
    Right x -> return x
    Left  e -> return (Left ([], CheckedException e))

-- | Catch and exception and observe the stack trace.
    If on top of the IO monad , this will also capture asynchronous exceptions
catchWithSrcLoc :: (Exception e, MonadBaseControl IO m) => EMT (Caught e l) m a -> (CallTrace -> e -> EMT l m a) -> EMT l m a
catchWithSrcLoc emt h = EMT $ do
                v <- unwrap emt
                case v of
                  Right x -> return (Right x)
                  Left (trace, CheckedException e) -> handle e trace
       where handle e trace =
                      case fromException e of
                               Nothing -> return (Left (trace,CheckedException e))
                               Just e' -> unEMT (h trace e')

instance (Exception e, MonadBaseControl IO m) => MonadCatch e (EMT (Caught e l) m) (EMT l m) where
  catchWithSrcLoc = catchWithSrcLoc
  catch           = catch

  | 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.
finally :: MonadBaseControl IO m => EMT l m a -> EMT l m b -> EMT l m a
finally m sequel = do { v <- m `onException` sequel; _ <- sequel; return v}


  | Like finally , but performs the second computation only when the first one
--   rises an exception
onException :: MonadBaseControl IO m => EMT l m a -> EMT l m b -> EMT l m a
onException m sequel = EMT $ do
                         ev <- unwrap m
                         case ev of
                           Left{}  -> do { _ <- unEMT sequel; return ev}
                           Right{} -> return ev

bracket :: MonadBaseControl IO m =>
                   EMT l m a        -- ^ acquire resource
                   -> (a -> EMT l m b) -- ^ release resource
                   -> (a -> EMT l m c) -- ^ computation
                   -> EMT l m c
bracket acquire release run = do { k <- acquire; run k `finally` release k }


  | Capture an exception e , wrap it , and rethrow .
--   Keeps the original monadic call trace.
wrapException :: (Exception e, Throws e' l, MonadBaseControl IO m) =>
                 (e -> e') -> EMT (Caught e l) m a -> EMT l m a
wrapException mkE m = m `catchWithSrcLoc` \loc e -> rethrow loc (mkE e)

 * Important trivia
 ** Hierarchies of Exceptions
 $hierarchies
 ** Unchecked exceptions
 *** Unchecked exceptions
 $unchecked
 ** Stack Traces
 $stacktraces
 $errors
 * The EM monad
 * The EMT monad transformer
 ** The Throws type class
 * Exception primitives
 $hierarchies
 If exceptions are hierarchical then you need to
   teach 'Throws' about the hierarchy. See the documentation of
   'Throws' for more info.

 Running main produces the output : 
 Running main produces the output:
 Defined at .. /Control / Monad / Exception / Throws.hs:46:9 - 45 
 Defined at .. /Control / Monad / Exception / Throws.hs:47:9 - 44 
 Defined at ../Control/Monad/Exception/Throws.hs:46:9-45
 Defined at ../Control/Monad/Exception/Throws.hs:47:9-44
 | The catch primitive
 | Catch and exception and observe the stack trace.
   and then the exception is rethrown.
   rises an exception
 ^ acquire resource
 ^ release resource
 ^ computation
   Keeps the original monadic call trace.
# LANGUAGE CPP #

| 
 A monad transformer for explicitly typed checked exceptions with support for asynchronous exception handling . Explicit exceptions are supported by the ideas described in : 

   *   , \"Explicitly Typed Exceptions for Haskell\ " , 
     PADL'10 , January 2010 , < -Typed-Exceptions-for-Haskell-PADL-10 > 

 The exceptions thrown by a computation are inferred by the typechecker 
 and appear in the type signature of the computation as ' Throws ' constraints . 

 Support for asynchronous exceptions is provided by the monad - control package . 

   /Example/ 

   > data DivideByZero = DivideByZero deriving ( Show ,  ) 
   > data SumOverflow   = SumOverflow   deriving ( Show ,  ) 
  
   > instance Exception DivideByZero 
   > instance Exception SumOverflow 
  
   > data Expr = Add   |    |   

   > eval (   )      = 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  else return ( v1 / v2 ) 

   GHCi infers the following types 
  
   > eval                                              : : ( Throws  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 

A monad transformer for explicitly typed checked exceptions with support for asynchronous exception handling. Explicit exceptions are supported by the ideas described in:

  * Jose Iborra, \"Explicitly Typed Exceptions for Haskell\",
    PADL'10, January 2010, <-Typed-Exceptions-for-Haskell-PADL-10>

The exceptions thrown by a computation are inferred by the typechecker
and appear in the type signature of the computation as 'Throws' constraints.

Support for asynchronous exceptions is provided by the monad-control package.

  /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
-}

module Control.Monad.Exception.IO (



  * * Understanding GHC errors

    EM,  tryEM, tryEMWithLoc, runEM, runEMParanoid,

    EMT(..), CallTrace, tryEMT, tryEMTWithLoc, runEMT, runEMTParanoid, AnyException, UncaughtException,

   Throws, Caught,

      throw, rethrow, catch, catchWithSrcLoc,
    finally, onException, bracket, wrapException,

    showExceptionWithTrace,
    FailException(..), MonadZeroException(..), mplusDefault,

  * 
    Exception(..), SomeException(..), Typeable,
    Failure(..),
#if !MIN_VERSION_failure(0,2,0)
    Try(..), NothingException(..),
    WrapFailure(..),
#endif
) where

import Control.Monad.Exception.Base
import Control.Monad.Exception.Throws
import Control.Monad.Exception.Catch (Exception, SomeException, fromException, MonadCatch)
import qualified Control.Monad.Exception.Catch
import Control.Failure
import Control.Monad.Trans.Control
import Data.Typeable
import Control.Exception.Lifted as CE (try)

  $ unchecked 
 An exception  can be declared as unchecked by making  an instance of 
    ' UncaughtException ' . 

 > instance UncaughtException E 

     will still appear in the list of exceptions thrown 
    by a computation but '  ' will not complain if  escapes the computation 
    being run . 

 Also , ' tryEMT ' allows you to run a computation regardless of the exceptions it throws . 

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.
-}


  $ stacktraces 
  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  
 >        g a   = do f a 
 > 
 >        main = runEMT $ do 
 >                 g ( ) ` catchWithSrcLoc ` 
 >                         \loc ( e::MyException ) - > lift(putStrLn$ showExceptionWithTrace  e ) 


 >        * 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 ) 


 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)


>       *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)

-}


  $ 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 :  ( ) 

 is the type checker saying : 

 \"hey , you are trying to run a computation which throws a @MyException@ without handling it , and I wo n'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 ) 
 >       instance ( Exception e ) = > Throws e ( Caught e l ) 
 >     ( 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 . 

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)
>      instance (Exception e) => Throws e (Caught e l)
>    (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.
-}


catch :: (Exception e, MonadBaseControl IO m) => EMT (Caught e l) m a -> (e -> EMT l m a) -> EMT l m a
catch emt h = catchWithSrcLoc emt (const h)

unwrap :: MonadBaseControl IO m => EMT l m a -> m (Either (CallTrace, CheckedException l) a)
unwrap m = do
  v <- CE.try $ unEMT m
  case v of
    Right x -> return x
    Left  e -> return (Left ([], CheckedException e))

    If on top of the IO monad , this will also capture asynchronous exceptions
catchWithSrcLoc :: (Exception e, MonadBaseControl IO m) => EMT (Caught e l) m a -> (CallTrace -> e -> EMT l m a) -> EMT l m a
catchWithSrcLoc emt h = EMT $ do
                v <- unwrap emt
                case v of
                  Right x -> return (Right x)
                  Left (trace, CheckedException e) -> handle e trace
       where handle e trace =
                      case fromException e of
                               Nothing -> return (Left (trace,CheckedException e))
                               Just e' -> unEMT (h trace e')

instance (Exception e, MonadBaseControl IO m) => MonadCatch e (EMT (Caught e l) m) (EMT l m) where
  catchWithSrcLoc = catchWithSrcLoc
  catch           = catch

  | Sequence two computations discarding the result of the second one .
    If the first computation rises an exception , the second computation is run
finally :: MonadBaseControl IO m => EMT l m a -> EMT l m b -> EMT l m a
finally m sequel = do { v <- m `onException` sequel; _ <- sequel; return v}


  | Like finally , but performs the second computation only when the first one
onException :: MonadBaseControl IO m => EMT l m a -> EMT l m b -> EMT l m a
onException m sequel = EMT $ do
                         ev <- unwrap m
                         case ev of
                           Left{}  -> do { _ <- unEMT sequel; return ev}
                           Right{} -> return ev

bracket :: MonadBaseControl IO m =>
                   -> EMT l m c
bracket acquire release run = do { k <- acquire; run k `finally` release k }


  | Capture an exception e , wrap it , and rethrow .
wrapException :: (Exception e, Throws e' l, MonadBaseControl IO m) =>
                 (e -> e') -> EMT (Caught e l) m a -> EMT l m a
wrapException mkE m = m `catchWithSrcLoc` \loc e -> rethrow loc (mkE e)
