control-monad-exception 0.4.8 → 0.5
raw patch · 5 files changed
+291/−223 lines, 5 filesdep +control-monad-failuredep +monadlocdep −template-haskell
Dependencies added: control-monad-failure, monadloc
Dependencies removed: template-haskell
Files
- Control/Monad/Exception.hs +158/−72
- Control/Monad/Exception/Catch.hs +74/−0
- Control/Monad/Exception/Class.hs +0/−120
- Control/Monad/Exception/Throws.hs +36/−12
- control-monad-exception.cabal +23/−19
Control/Monad/Exception.hs view
@@ -1,10 +1,8 @@ {-# LANGUAGE DeriveDataTypeable #-}+{-# LANGUAGE ExistentialQuantification, ScopedTypeVariables #-} {-# LANGUAGE UndecidableInstances #-} {-# LANGUAGE FlexibleInstances, TypeSynonymInstances #-} {-# LANGUAGE MultiParamTypeClasses #-}-{-# LANGUAGE OverlappingInstances #-}-{-# LANGUAGE TemplateHaskell #-}-{-# LANGUAGE NamedFieldPuns #-} {-| A Monad Transformer for explicitly typed checked exceptions.@@ -78,59 +76,86 @@ * If your sets of exceptions are hierarchical then you need to teach 'Throws' about the hierarchy. -> -- TopException-> -- |-> instance Throws MidException TopException -- |-> -- MidException-> instance Throws ChildException MidException -- |-> instance Throws ChildException TopException -- |-> -- ChildException+> -- TopException+> -- |+> instance Throws MidException (Caught TopException l) -- |+> -- MidException+> instance Throws ChildException (Caught MidException l) -- |+> instance Throws ChildException (Caught TopException l) -- |+ > -- ChildException - * Stack traces are only provided for explicitly annotated program points.- For now there is the TH macro 'withLocTH' to help with this.- Eventually a preprocessor could be written to automatically insert calls- to 'withLoc' at every do statement.+ * 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: -> f () = $withLocTH $ throw MyException-> g a = $withLocTH $ f a+> {-# 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 $ $withLocTH $ do-> g () `catchWithSrcLoc` \loc (e::MyException) -> lift(putStrLn$ showExceptionWithTrace loc e)+> main = runEMT $ do+> g () `catchWithSrcLoc`+> \loc (e::MyException) -> lift(putStrLn$ showExceptionWithTrace loc e) > -- Running main produces the output: > *Main> main > MyException-> in Main(example.hs): (12,6)-> Main(example.hs): (11,7)-+> 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) -} module Control.Monad.Exception (++-- * The EM monad EM, tryEM, runEM, runEMParanoid,- EMT, tryEMT, runEMT, runEMTParanoid,- WithSrcLoc(..), withLocTH,- MonadZeroException(..),- module Control.Monad.Exception.Class ) where +-- * The EMT monad transformer+ EMT, CallTrace, tryEMT, runEMT, runEMTParanoid,++-- * Exception primitives+ throw, rethrow, Control.Monad.Exception.catch, Control.Monad.Exception.catchWithSrcLoc,+ finally, onException, bracket, wrapException,++ showExceptionWithTrace,+ FailException(..), MonadZeroException(..),++-- * The Try class for absorbing other error monads+ Try(..), NothingException(..),++-- * Reexports+ Exception(..), SomeException(..), Typeable(..),+ MonadFailure(..),+ Throws, Caught, UncaughtException,+ withLoc, withLocTH,++) where+ import Control.Applicative+import qualified Control.Exception as CE import Control.Monad.Identity-import Control.Monad.Exception.Class+import Control.Monad.Exception.Catch import Control.Monad.Fix import Control.Monad.Trans import Control.Monad.Cont.Class import Control.Monad.RWS.Class+import Control.Monad.Loc+import Control.Monad.Failure import Data.Monoid import Data.Typeable-import Language.Haskell.TH.Syntax hiding (lift) import Text.PrettyPrint import Prelude hiding (catch) -- | A monad of explicitly typed, checked exceptions type EM l = EMT l Identity - mapLeft :: (a -> b) -> Either a r -> Either b r mapLeft f (Left x) = Left (f x) mapLeft _ (Right x) = Right x@@ -147,21 +172,21 @@ runEMParanoid :: EM ParanoidMode a -> a runEMParanoid = runIdentity . runEMTParanoid -data MonadZeroException = MonadZeroException deriving (Show, Typeable)-instance Exception MonadZeroException+type CallTrace = [String] -newtype EMT l m a = EMT {unEMT :: m (Either ([String], WrapException l) a)}+newtype EMT l m a = EMT {unEMT :: m (Either (CallTrace, CheckedException l) a)} type AnyException = Caught SomeException -- | Run a computation explicitly handling exceptions tryEMT :: Monad m => EMT (AnyException l) m a -> m (Either SomeException a)-tryEMT (EMT m) = mapLeft (unwrapException.snd) `liftM` m+tryEMT (EMT m) = mapLeft (checkedException.snd) `liftM` m -runEMT_gen :: Monad m => EMT l m a -> m a-runEMT_gen (EMT m) = liftM f m where- f (Right x) = x- f (Left (loc,e)) = error (showExceptionWithTrace loc (unwrapException e))+runEMT_gen :: forall l m a . Monad m => EMT l m a -> m a+runEMT_gen (EMT m) = m >>= \x ->+ case x of+ Right x -> return x+ Left (loc,e) -> error (showExceptionWithTrace loc (checkedException e)) -- | Run a safe computation runEMT :: Monad m => EMT NoExceptions m a -> m a@@ -180,6 +205,9 @@ instance Monad m => Monad (EMT l m) where return = EMT . return . Right++ fail s = EMT $ return $ Left ([], CheckedException $ toException $ FailException s)+ emt >>= f = EMT $ do v <- unEMT emt case v of@@ -190,52 +218,77 @@ pure = return (<*>) = ap -instance (Exception e, Throws e l, Monad m) => MonadThrow e (EMT l m) where- throw = EMT . return . (\e -> Left ([],e)) . WrapException . toException+instance (Exception e, Throws e l, Monad m) => MonadFailure e (EMT l m) where+ failure = throw+ instance (Exception e, Monad m) => MonadCatch e (EMT (Caught e l) m) (EMT l m) where- catchWithSrcLoc = catchEMT- catch emt h = catchEMT emt (\_ -> h)+ catchWithSrcLoc = Control.Monad.Exception.catchWithSrcLoc+ catch = Control.Monad.Exception.catch -catchEMT :: (Exception e, Monad m) => EMT (Caught e l) m a -> ([String] -> e -> EMT l m a) -> EMT l m a-catchEMT emt h = EMT $ do+instance Monad m => MonadLoc (EMT l m) where+ withLoc loc (EMT emt) = EMT $ do+ current <- emt+ case current of+ (Left (tr, a)) -> return (Left (loc:tr, a))+ _ -> return current++-- | The throw primitive+throw :: (Exception e, Throws e l, Monad m) => e -> EMT l m a+throw = EMT . return . (\e -> Left ([],e)) . CheckedException . toException++-- | Rethrow an exception keeping the call trace+rethrow :: (Throws e l, Monad m) => CallTrace -> e -> EMT l m a+rethrow callt = EMT . return . (\e -> Left (callt,e)) . CheckedException . toException+++-- | The catch primitive+catch :: (Exception e, Monad m) => EMT (Caught e l) m a -> (e -> EMT l m a) -> EMT l m a+catch emt h = Control.Monad.Exception.catchWithSrcLoc emt (\_ -> h)++-- | Like 'Control.Monad.Exception.catch' but makes the call trace available+catchWithSrcLoc :: (Exception e, Monad m) => EMT (Caught e l) m a -> (CallTrace -> e -> EMT l m a) -> EMT l m a+catchWithSrcLoc emt h = EMT $ do v <- unEMT emt case v of Right x -> return (Right x)- Left (trace, WrapException e) -> case fromException e of- Nothing -> return (Left (trace,WrapException e))+ Left (trace, CheckedException e) -> case fromException e of+ Nothing -> return (Left (trace,CheckedException e)) Just e' -> unEMT (h trace e') --- | 'withLocTH' is a convenient TH macro which expands to 'withLoc' @\<source location\>@--- Usage:------ > f x = $withLocTH $ do-withLocTH :: Q Exp-withLocTH = do- loc <- qLocation- let loc_msg = showLoc loc- [| withLoc loc_msg |]- where- showLoc Loc{loc_module, loc_filename, loc_start} = render $- {- text loc_package <> char '.' <> -}- text loc_module <> parens (text loc_filename) <> colon <+> text (show loc_start) --- | Generating stack traces for exceptions-class WithSrcLoc a where- -- | 'withLoc' records the given source location in the exception stack trace- -- when used to wrap a EMT computation.- --- -- On any other monad or value, 'withLoc' is defined as the identity- withLoc :: String -> a -> a+-- | 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 :: Monad m => EMT l m a -> EMT l m b -> EMT l m a+finally m sequel = do { v <- m `onException` sequel; sequel; return v} -instance WithSrcLoc a where withLoc _ = id -instance Monad m => WithSrcLoc (EMT l m a) where- withLoc loc (EMT emt) = EMT $ do- current <- emt- case current of- (Left (tr, a)) -> return (Left (loc:tr, a))- _ -> return current+-- | Like finally, but performs the second computation only when the first one+-- rises an exception+onException :: Monad m => EMT l m a -> EMT l m b -> EMT l m a+onException (EMT m) (EMT sequel) = EMT $ do+ ev <- m+ case ev of+ Left{} -> do { sequel; return ev}+ Right{} -> return ev +bracket :: 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+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, Monad m) => EMT (Caught e l) m a -> (e -> e') -> EMT l m a+wrapException m mkE = m `Control.Monad.Exception.catchWithSrcLoc` \loc e -> rethrow loc (mkE e)++showExceptionWithTrace :: Exception e => [String] -> e -> String+showExceptionWithTrace [] e = show e+showExceptionWithTrace trace e = render$+ text (show e) $$+ text " in" <+> (vcat (map text $ reverse trace))+ instance (Throws MonadZeroException l) => MonadPlus (EM l) where mzero = throw MonadZeroException mplus emt1 emt2 = EMT$ do@@ -250,9 +303,42 @@ mfix f = EMT $ mfix $ \a -> unEMT $ f $ case a of Right r -> r _ -> error "empty fix argument"+instance UncaughtException SomeException instance (Throws SomeException l, MonadIO m) => MonadIO (EMT l m) where- liftIO = lift . liftIO+ liftIO m = EMT (liftIO m') where+ m' = liftM Right m+ `CE.catch`+ \(e::SomeException) -> return (Left ([], CheckedException e))+++-- -----------------------------------------------+-- The Try class for absorbing other error monads+-- -----------------------------------------------+data NothingException = NothingException deriving (Typeable, Show)+instance Exception NothingException++class Try m l where try :: Monad m' => m a -> EMT l m' a+instance Throws NothingException l => Try Maybe l where try = maybe (throw NothingException) return+instance (Exception e, Throws e l) => Try (Either e) l where try = either throw return++instance (Monad m, Try m l) => Try (EMT l m) l where try = join . fmap (EMT . return) .try . unEMT++-- -----------+-- Exceptions+-- -----------++-- | @FailException@ is thrown by Monad 'fail'+data FailException = FailException String deriving (Show, Typeable)+instance Exception FailException++-- | @MonadZeroException@ is thrown by MonadPlus 'mzero'+data MonadZeroException = MonadZeroException deriving (Show, Typeable)+instance Exception MonadZeroException++-- ------------------+-- mtl boilerplate+-- ------------------ instance MonadCont m => MonadCont (EMT l m) where callCC f = EMT $ callCC $ \c -> unEMT (f (\a -> EMT $ c (Right a)))
+ Control/Monad/Exception/Catch.hs view
@@ -0,0 +1,74 @@+{-# LANGUAGE CPP #-}+{-# LANGUAGE UndecidableInstances #-}+{-# LANGUAGE EmptyDataDecls #-}+{-# LANGUAGE MultiParamTypeClasses #-}+{-# LANGUAGE FunctionalDependencies #-}+{-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE ExistentialQuantification #-}+{-# LANGUAGE OverlappingInstances #-}+++{-| Defines the (not so useful anymore) 'MonadCatch' type class.+-}++module Control.Monad.Exception.Catch (+ module Control.Monad,+ module Control.Monad.Exception.Throws,+ MonadCatch(..),+ Exception(..), SomeException(..),+ ) where++import Control.Monad+#if TRANSFORMERS+import Control.Monad.Trans.Error+import Control.Monad.Trans.List+import Control.Monad.Trans.Reader+import Control.Monad.Trans.State+import Control.Monad.Trans.Writer+import Control.Monad.Trans.RWS+#else+import Control.Monad.Error+import Control.Monad.List+import Control.Monad.Reader+import Control.Monad.State+import Control.Monad.Writer+import Control.Monad.RWS+#endif++#if __GLASGOW_HASKELL__ < 610+import Control.Exception.Extensible (Exception(..), SomeException)+import qualified Control.Exception.Extensible as Control.Exception+#else+import Control.Exception (Exception(..), SomeException)+import qualified Control.Exception+#endif+import Data.Monoid++import Control.Monad.Exception.Throws++import Prelude hiding (catch)++class (Monad m, Monad m') => MonadCatch e m m' | e m -> m', e m' -> m where+ catch :: m a -> (e -> m' a) -> m' a+ catchWithSrcLoc :: m a -> ([String] -> e -> m' a) -> m' a+ catchWithSrcLoc m h = catch m (h [])++instance Exception e => MonadCatch e IO IO where+ catch = Control.Exception.catch++-- Throw and Catch instances for the Either and ErrorT monads+-- -----------------------------------------------------------+instance (Error e) => MonadCatch e (Either e) (Either e) where catch m h = either h Right m+instance (Error e, Monad m) => MonadCatch e (ErrorT e m) (ErrorT e m) where catch = catchError+++-- Instances for transformers (requires undecidable instances in some cases)+-- -------------------------------------------------------------------------+instance MonadCatch e m m' => MonadCatch e (ListT m) (ListT m') where catch (ListT m) h = ListT (catch m (runListT . h))+instance MonadCatch e m m' => MonadCatch e (ReaderT r m) (ReaderT r m') where catch (ReaderT m) h = ReaderT (\s -> catch (m s) ((`runReaderT` s) . h))++instance (Monoid w, MonadCatch e m m') => MonadCatch e (WriterT w m) (WriterT w m') where catch (WriterT m) h = WriterT (catch m (runWriterT . h))++instance MonadCatch e m m' => MonadCatch e (StateT s m) (StateT s m') where catch (StateT m) h = StateT (\s -> catch (m s) ((`runStateT` s) . h))++instance (Monoid w, MonadCatch e m m') => MonadCatch e (RWST r w s m) (RWST r w s m') where catch (RWST m) h = RWST (\r s -> catch (m r s) ((\m -> runRWST m r s) . h))
− Control/Monad/Exception/Class.hs
@@ -1,120 +0,0 @@-{-# LANGUAGE CPP #-}-{-# LANGUAGE UndecidableInstances #-}-{-# LANGUAGE EmptyDataDecls #-}-{-# LANGUAGE MultiParamTypeClasses #-}-{-# LANGUAGE FunctionalDependencies #-}-{-# LANGUAGE FlexibleInstances #-}-{-# LANGUAGE ExistentialQuantification #-}-{-# LANGUAGE DeriveDataTypeable #-}-{-# LANGUAGE OverlappingInstances #-}---{-| Defines 'MonadThrow' and 'MonadCatch' type classes and suitable instances for 'IO' and 'Either'.--}--module Control.Monad.Exception.Class (- module Control.Monad,- module Control.Monad.Exception.Throws,- MonadThrow(..), MonadCatch(..),- WrapException(..), Exception(..), SomeException(..),- showExceptionWithTrace, wrapException- ) where--import Control.Monad-#if TRANSFORMERS-import Control.Monad.Trans-import Control.Monad.Trans.Error-import Control.Monad.Trans.List-import Control.Monad.Trans.Reader-import Control.Monad.Trans.State-import Control.Monad.Trans.Writer-import Control.Monad.Trans.RWS-#else-import Control.Monad.Error-import Control.Monad.List-import Control.Monad.Reader-import Control.Monad.State-import Control.Monad.Writer-import Control.Monad.RWS-#endif--#if __GLASGOW_HASKELL__ < 610-import Control.Exception.Extensible (Exception(..), SomeException)-import qualified Control.Exception.Extensible as Control.Exception-#else-import Control.Exception (Exception(..), SomeException)-import qualified Control.Exception-#endif-import Data.Monoid-import Data.Typeable-import Text.PrettyPrint--import Control.Monad.Exception.Throws--import Prelude hiding (catch)--class Monad m => MonadThrow e m where- throw :: e -> m a- throwWithSrcLoc :: String -> e -> m a- throwWithSrcLoc _ = throw--instance Exception e => MonadThrow e IO where- throw = Control.Exception.throw--class (Monad m, Monad m') => MonadCatch e m m' | e m -> m', e m' -> m where- catch :: m a -> (e -> m' a) -> m' a- catchWithSrcLoc :: m a -> ([String] -> e -> m' a) -> m' a- catchWithSrcLoc m h = catch m (h [])--instance Exception e => MonadCatch e IO IO where- catch = Control.Exception.catch--wrapException ::- (MonadThrow e' m', MonadCatch e m m') =>- m a -> (e -> e') -> m' a-wrapException m mkE = m `catch` (throw . mkE)--{-| Given a list of source locations and an exception, @showExceptionWithTrace@ produces output of the form--> <exception details>-> in <module a>(<file a.hs>): (12,6)-> <module b>(<file b.hs>): (11,7)-> ...---}-showExceptionWithTrace :: Exception e => [String] -> e -> String-showExceptionWithTrace trace e = render$- text (show e) $$- text " in" <+> (vcat (map text $ reverse trace))---- Labelled SomeException--- --------------------------- | @WrapException@ adds a phantom type parameter @l@ to @SomeException@-newtype WrapException l = WrapException {unwrapException::SomeException} deriving (Typeable)-instance Show (WrapException l) where show (WrapException e) = show e---- Throw and Catch instances for the Either and ErrorT monads--- ------------------------------------------------------------instance (Error e) => MonadThrow e (Either e) where throw = Left-instance (Error e) => MonadCatch e (Either e) (Either e) where catch m h = either h Right m--instance (Error e, Monad m) => MonadThrow e (ErrorT e m) where throw = throwError-instance (Error e, Monad m) => MonadCatch e (ErrorT e m) (ErrorT e m) where catch = catchError----- Instances for transformers (requires undecidable instances in some cases)--- --------------------------------------------------------------------------instance MonadThrow e m => MonadThrow e (ListT m) where throw = lift . throw-instance MonadCatch e m m' => MonadCatch e (ListT m) (ListT m') where catch (ListT m) h = ListT (catch m (runListT . h))--instance MonadThrow e m => MonadThrow e (ReaderT r m) where throw = lift . throw-instance MonadCatch e m m' => MonadCatch e (ReaderT r m) (ReaderT r m') where catch (ReaderT m) h = ReaderT (\s -> catch (m s) ((`runReaderT` s) . h))--instance (Monoid w, MonadThrow e m) => MonadThrow e (WriterT w m) where throw = lift . throw-instance (Monoid w, MonadCatch e m m') => MonadCatch e (WriterT w m) (WriterT w m') where catch (WriterT m) h = WriterT (catch m (runWriterT . h))--instance MonadThrow e m => MonadThrow e (StateT s m) where throw = lift . throw-instance MonadCatch e m m' => MonadCatch e (StateT s m) (StateT s m') where catch (StateT m) h = StateT (\s -> catch (m s) ((`runStateT` s) . h))--instance (Monoid w, MonadThrow e m) => MonadThrow e (RWST r w s m) where throw = lift . throw-instance (Monoid w, MonadCatch e m m') => MonadCatch e (RWST r w s m) (RWST r w s m') where catch (RWST m) h = RWST (\r s -> catch (m r s) ((\m -> runRWST m r s) . h))
Control/Monad/Exception/Throws.hs view
@@ -2,19 +2,24 @@ {-# LANGUAGE EmptyDataDecls #-} {-# LANGUAGE MultiParamTypeClasses #-} {-# LANGUAGE OverlappingInstances, FlexibleInstances #-}+{-# LANGUAGE UndecidableInstances #-} {-| Defines the @Throws@ binary relationship between types. -} -module Control.Monad.Exception.Throws (Throws, Caught, UncaughtException, NoExceptions, ParanoidMode) where+module Control.Monad.Exception.Throws (+ Throws, Caught,+ CheckedException(..),+ UncaughtException,+ NoExceptions, ParanoidMode) where #if __GLASGOW_HASKELL__ < 610 import Control.Exception.Extensible (Exception(..), SomeException) #else import Control.Exception (Exception(..), SomeException) #endif-+import Data.Typeable -- | A type level witness of a exception handler. data Caught e l@@ -45,18 +50,17 @@ 'Throws' is not a transitive relation and every ancestor relation must be explicitly encoded. -> -- TopException-> -- |-> instance Throws MidException TopException -- |-> -- MidException-> instance Throws ChildException MidException -- |-> instance Throws ChildException TopException -- |-> -- ChildException+> -- 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. - -} class (Private l, Exception e) => Throws e l@@ -68,17 +72,37 @@ -- . -- Capturing SomeException captures every possible exception instance Exception e => Throws e (Caught SomeException l)+instance Throws SomeException (Caught SomeException l) -- Disambiguation instance -- | Uncaught Exceptions model unchecked exceptions (a la RuntimeException in Java) ----- In order to declare an unchecked exception @e@,+-- 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 using an instance of @Throws@:+--+-- > instance Throws E l+--+-- The shortcoming of this route is that runEMTParanoid won't be able to+-- control exceptions declared unchecked this way.+-} class Exception e => UncaughtException e instance UncaughtException e => Throws e NoExceptions - data NoExceptions instance Private NoExceptions data ParanoidMode instance Private ParanoidMode++-- Labelled SomeException+-- ------------------------+-- | @CheckedException@ adds a phantom type parameter @l@ to @SomeException@+newtype CheckedException l = CheckedException {checkedException::SomeException} deriving (Typeable)+instance Show (CheckedException l) where show (CheckedException e) = show e
control-monad-exception.cabal view
@@ -1,5 +1,5 @@ name: control-monad-exception-version: 0.4.8+version: 0.5 Cabal-Version: >= 1.2.3 build-type: Simple license: PublicDomain@@ -38,27 +38,29 @@ > runEM(eval `catch` \ (e::SomeException) -> return (-1)) :: Expr -> Double . .- This package provides, among other things:+ In addition to explicitly typed exceptions his package provides: . * Support for explicitly documented, unchecked exceptions (with 'tryEM'). . * Support for selective unchecked exceptions (with 'UncaughtException'). .- * Support for exception stack traces (experimental). /Example:/+ * Support for exception call traces via 'Control.Monad.Loc.MonadLoc'. /Example:/ .- > f () = $withLocTH $ throw MyException- > g a = $withLocTH $ f a >- > main = runEMT $ $withLocTH $ do- > g () `catchWithSrcLoc` \loc (e::MyException) -> lift(putStrLn$ showExceptionWithTrace loc e)- .- > -- Running main produces the output:- .- > *Main> main- > MyException- > in Main(example.hs): (12,6)- > Main(example.hs): (11,7)- .+ > 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) synopsis: Explicitly typed, checked exceptions with stack traces category: Control, Monads@@ -76,7 +78,9 @@ default: False Library- buildable: True+ buildable: True + build-depends: control-monad-failure, monadloc, pretty+ if flag(extensibleExceptions) build-depends: extensible-exceptions >= 0.1 && <0.2,@@ -99,9 +103,9 @@ EmptyDataDecls, DeriveDataTypeable, UndecidableInstances- build-depends: pretty, template-haskell+ exposed-modules:- Control.Monad.Exception.Class+ Control.Monad.Exception.Catch Control.Monad.Exception.Throws Control.Monad.Exception- ghc-options: -Wall -fno-warn-name-shadowing+ ghc-options: -Wall -fno-warn-name-shadowing -fno-warn-orphans