control-monad-exception 0.10.3.1 → 0.11.1
raw patch · 7 files changed
+501/−277 lines, 7 filesdep +lifted-basedep +monad-controldep +transformers-basePVP ok
version bump matches the API change (PVP)
Dependencies added: lifted-base, monad-control, transformers-base
API changes (from Hackage documentation)
- Control.Monad.Exception: EMT :: m (Either (CallTrace, CheckedException l) a) -> EMT l m a
- Control.Monad.Exception: FailException :: String -> FailException
- Control.Monad.Exception: MonadZeroException :: MonadZeroException
- Control.Monad.Exception: SomeException :: e -> SomeException
- Control.Monad.Exception: bracket :: Monad m => EMT l m a -> (a -> EMT l m b) -> (a -> EMT l m c) -> EMT l m c
- Control.Monad.Exception: catch :: (Exception e, Monad m) => EMT (Caught e l) m a -> (e -> EMT l m a) -> EMT l m a
- Control.Monad.Exception: catchWithSrcLoc :: (Exception e, Monad m) => EMT (Caught e l) m a -> (CallTrace -> e -> EMT l m a) -> EMT l m a
- Control.Monad.Exception: class (Typeable e, Show e) => Exception e
- Control.Monad.Exception: class Monad f => Failure e (f :: * -> *)
- Control.Monad.Exception: class Monad m => MonadLoc (m :: * -> *)
- Control.Monad.Exception: class Exception e => Throws e l
- Control.Monad.Exception: class Typeable a
- Control.Monad.Exception: class Exception e => UncaughtException e
- Control.Monad.Exception: data AnyException
- Control.Monad.Exception: data Caught e l
- Control.Monad.Exception: data FailException
- Control.Monad.Exception: data MonadZeroException
- Control.Monad.Exception: data SomeException :: *
- Control.Monad.Exception: failure :: Failure e f => e -> f v
- Control.Monad.Exception: finally :: Monad m => EMT l m a -> EMT l m b -> EMT l m a
- Control.Monad.Exception: fromException :: Exception e => SomeException -> Maybe e
- Control.Monad.Exception: mplusDefault :: Monad m => EMT l m a -> EMT l m a -> EMT l m a
- Control.Monad.Exception: newtype EMT l m a
- Control.Monad.Exception: onException :: Monad m => EMT l m a -> EMT l m b -> EMT l m a
- Control.Monad.Exception: rethrow :: (Throws e l, Monad m) => CallTrace -> e -> EMT l m a
- Control.Monad.Exception: runEM :: EM NoExceptions a -> a
- Control.Monad.Exception: runEMParanoid :: EM ParanoidMode a -> a
- Control.Monad.Exception: runEMT :: Monad m => EMT NoExceptions m a -> m a
- Control.Monad.Exception: runEMTParanoid :: Monad m => EMT ParanoidMode m a -> m a
- Control.Monad.Exception: showExceptionWithTrace :: Exception e => [String] -> e -> String
- Control.Monad.Exception: throw :: (Exception e, Throws e l, Monad m) => e -> EMT l m a
- Control.Monad.Exception: toException :: Exception e => e -> SomeException
- Control.Monad.Exception: tryEM :: EM AnyException a -> Either SomeException a
- Control.Monad.Exception: tryEMT :: Monad m => EMT AnyException m a -> m (Either SomeException a)
- Control.Monad.Exception: type CallTrace = [String]
- Control.Monad.Exception: type EM l = EMT l Identity
- Control.Monad.Exception: typeOf :: Typeable a => a -> TypeRep
- Control.Monad.Exception: unEMT :: EMT l m a -> m (Either (CallTrace, CheckedException l) a)
- Control.Monad.Exception: withLoc :: MonadLoc m => String -> m a -> m a
- Control.Monad.Exception: withLocTH :: Q Exp
- Control.Monad.Exception: wrapException :: (Exception e, Throws e' l, Monad m) => (e -> e') -> EMT (Caught e l) m a -> EMT l m a
- Control.Monad.Exception.Base: bracket :: Monad m => EMT l m a -> (a -> EMT l m b) -> (a -> EMT l m c) -> EMT l m c
- Control.Monad.Exception.Base: catch :: (Exception e, Monad m) => EMT (Caught e l) m a -> (e -> EMT l m a) -> EMT l m a
- Control.Monad.Exception.Base: catchWithSrcLoc :: (Exception e, Monad m) => EMT (Caught e l) m a -> (CallTrace -> e -> EMT l m a) -> EMT l m a
- Control.Monad.Exception.Base: finally :: Monad m => EMT l m a -> EMT l m b -> EMT l m a
- Control.Monad.Exception.Base: instance [overlap ok] (Exception e, Monad m) => MonadCatch e (EMT (Caught e l) m) (EMT l m)
- Control.Monad.Exception.Base: instance [overlap ok] (Throws SomeException l, MonadIO m) => MonadIO (EMT l m)
- Control.Monad.Exception.Base: onException :: Monad m => EMT l m a -> EMT l m b -> EMT l m a
- Control.Monad.Exception.Base: runEMT_gen :: Monad m => EMT l m a -> m a
- Control.Monad.Exception.Base: wrapException :: (Exception e, Throws e' l, Monad m) => (e -> e') -> EMT (Caught e l) m a -> EMT l m a
+ Control.Monad.Exception.Base: instance [overlap ok] MonadBase b m => MonadBase b (EMT l m)
+ Control.Monad.Exception.Base: instance [overlap ok] MonadBaseControl b m => MonadBaseControl b (EMT l m)
+ Control.Monad.Exception.Base: instance [overlap ok] MonadIO m => MonadIO (EMT l m)
+ Control.Monad.Exception.Base: instance [overlap ok] MonadTransControl (EMT l)
+ Control.Monad.Exception.Base: instance [overlap ok] Throws MonadZeroException l => Alternative (EM l)
+ Control.Monad.Exception.Base: runEMTGen :: Monad m => EMT l m a -> m a
+ Control.Monad.Exception.IO: EMT :: m (Either (CallTrace, CheckedException l) a) -> EMT l m a
+ Control.Monad.Exception.IO: FailException :: String -> FailException
+ Control.Monad.Exception.IO: MonadZeroException :: MonadZeroException
+ Control.Monad.Exception.IO: SomeException :: e -> SomeException
+ Control.Monad.Exception.IO: bracket :: MonadBaseControl IO m => EMT l m a -> (a -> EMT l m b) -> (a -> EMT l m c) -> EMT l m c
+ Control.Monad.Exception.IO: catch :: (Exception e, MonadBaseControl IO m) => EMT (Caught e l) m a -> (e -> EMT l m a) -> EMT l m a
+ Control.Monad.Exception.IO: catchWithSrcLoc :: (Exception e, MonadBaseControl IO m) => EMT (Caught e l) m a -> (CallTrace -> e -> EMT l m a) -> EMT l m a
+ Control.Monad.Exception.IO: class (Typeable e, Show e) => Exception e
+ Control.Monad.Exception.IO: class Monad f => Failure e (f :: * -> *)
+ Control.Monad.Exception.IO: class Exception e => Throws e l
+ Control.Monad.Exception.IO: class Typeable a
+ Control.Monad.Exception.IO: class Exception e => UncaughtException e
+ Control.Monad.Exception.IO: data AnyException
+ Control.Monad.Exception.IO: data Caught e l
+ Control.Monad.Exception.IO: data FailException
+ Control.Monad.Exception.IO: data MonadZeroException
+ Control.Monad.Exception.IO: data SomeException :: *
+ Control.Monad.Exception.IO: failure :: Failure e f => e -> f v
+ Control.Monad.Exception.IO: finally :: MonadBaseControl IO m => EMT l m a -> EMT l m b -> EMT l m a
+ Control.Monad.Exception.IO: fromException :: Exception e => SomeException -> Maybe e
+ Control.Monad.Exception.IO: instance [overlap ok] (Exception e, MonadBaseControl IO m) => MonadCatch e (EMT (Caught e l) m) (EMT l m)
+ Control.Monad.Exception.IO: mplusDefault :: Monad m => EMT l m a -> EMT l m a -> EMT l m a
+ Control.Monad.Exception.IO: newtype EMT l m a
+ Control.Monad.Exception.IO: onException :: MonadBaseControl IO m => EMT l m a -> EMT l m b -> EMT l m a
+ Control.Monad.Exception.IO: rethrow :: (Throws e l, Monad m) => CallTrace -> e -> EMT l m a
+ Control.Monad.Exception.IO: runEM :: EM NoExceptions a -> a
+ Control.Monad.Exception.IO: runEMParanoid :: EM ParanoidMode a -> a
+ Control.Monad.Exception.IO: runEMT :: Monad m => EMT NoExceptions m a -> m a
+ Control.Monad.Exception.IO: runEMTParanoid :: Monad m => EMT ParanoidMode m a -> m a
+ Control.Monad.Exception.IO: showExceptionWithTrace :: Exception e => [String] -> e -> String
+ Control.Monad.Exception.IO: throw :: (Exception e, Throws e l, Monad m) => e -> EMT l m a
+ Control.Monad.Exception.IO: toException :: Exception e => e -> SomeException
+ Control.Monad.Exception.IO: tryEM :: EM AnyException a -> Either SomeException a
+ Control.Monad.Exception.IO: tryEMT :: Monad m => EMT AnyException m a -> m (Either SomeException a)
+ Control.Monad.Exception.IO: tryEMTWithLoc :: Monad m => EMT AnyException m a -> m (Either (CallTrace, SomeException) a)
+ Control.Monad.Exception.IO: tryEMWithLoc :: EM AnyException a -> Either (CallTrace, SomeException) a
+ Control.Monad.Exception.IO: type CallTrace = [String]
+ Control.Monad.Exception.IO: type EM l = EMT l Identity
+ Control.Monad.Exception.IO: unEMT :: EMT l m a -> m (Either (CallTrace, CheckedException l) a)
+ Control.Monad.Exception.IO: wrapException :: (Exception e, Throws e' l, MonadBaseControl IO m) => (e -> e') -> EMT (Caught e l) m a -> EMT l m a
+ Control.Monad.Exception.Pure: EMT :: m (Either (CallTrace, CheckedException l) a) -> EMT l m a
+ Control.Monad.Exception.Pure: FailException :: String -> FailException
+ Control.Monad.Exception.Pure: MonadZeroException :: MonadZeroException
+ Control.Monad.Exception.Pure: SomeException :: e -> SomeException
+ Control.Monad.Exception.Pure: bracket :: Monad m => EMT l m a -> (a -> EMT l m b) -> (a -> EMT l m c) -> EMT l m c
+ Control.Monad.Exception.Pure: catch :: (Exception e, Monad m) => EMT (Caught e l) m a -> (e -> EMT l m a) -> EMT l m a
+ Control.Monad.Exception.Pure: catchWithSrcLoc :: (Exception e, Monad m) => EMT (Caught e l) m a -> (CallTrace -> e -> EMT l m a) -> EMT l m a
+ Control.Monad.Exception.Pure: class (Typeable e, Show e) => Exception e
+ Control.Monad.Exception.Pure: class Monad f => Failure e (f :: * -> *)
+ Control.Monad.Exception.Pure: class Exception e => Throws e l
+ Control.Monad.Exception.Pure: class Typeable1 (t :: * -> *)
+ Control.Monad.Exception.Pure: class Exception e => UncaughtException e
+ Control.Monad.Exception.Pure: data AnyException
+ Control.Monad.Exception.Pure: data Caught e l
+ Control.Monad.Exception.Pure: data FailException
+ Control.Monad.Exception.Pure: data MonadZeroException
+ Control.Monad.Exception.Pure: data SomeException :: *
+ Control.Monad.Exception.Pure: failure :: Failure e f => e -> f v
+ Control.Monad.Exception.Pure: finally :: Monad m => EMT l m a -> EMT l m b -> EMT l m a
+ Control.Monad.Exception.Pure: fromException :: Exception e => SomeException -> Maybe e
+ Control.Monad.Exception.Pure: instance [overlap ok] (Exception e, Monad m) => MonadCatch e (EMT (Caught e l) m) (EMT l m)
+ Control.Monad.Exception.Pure: mplusDefault :: Monad m => EMT l m a -> EMT l m a -> EMT l m a
+ Control.Monad.Exception.Pure: newtype EMT l m a
+ Control.Monad.Exception.Pure: onException :: Monad m => EMT l m a -> EMT l m b -> EMT l m a
+ Control.Monad.Exception.Pure: rethrow :: (Throws e l, Monad m) => CallTrace -> e -> EMT l m a
+ Control.Monad.Exception.Pure: runEM :: EM NoExceptions a -> a
+ Control.Monad.Exception.Pure: runEMParanoid :: EM ParanoidMode a -> a
+ Control.Monad.Exception.Pure: runEMT :: Monad m => EMT NoExceptions m a -> m a
+ Control.Monad.Exception.Pure: runEMTParanoid :: Monad m => EMT ParanoidMode m a -> m a
+ Control.Monad.Exception.Pure: showExceptionWithTrace :: Exception e => [String] -> e -> String
+ Control.Monad.Exception.Pure: throw :: (Exception e, Throws e l, Monad m) => e -> EMT l m a
+ Control.Monad.Exception.Pure: toException :: Exception e => e -> SomeException
+ Control.Monad.Exception.Pure: tryEM :: EM AnyException a -> Either SomeException a
+ Control.Monad.Exception.Pure: tryEMT :: Monad m => EMT AnyException m a -> m (Either SomeException a)
+ Control.Monad.Exception.Pure: tryEMTWithLoc :: Monad m => EMT AnyException m a -> m (Either (CallTrace, SomeException) a)
+ Control.Monad.Exception.Pure: tryEMWithLoc :: EM AnyException a -> Either (CallTrace, SomeException) a
+ Control.Monad.Exception.Pure: type CallTrace = [String]
+ Control.Monad.Exception.Pure: type EM l = EMT l Identity
+ Control.Monad.Exception.Pure: unEMT :: EMT l m a -> m (Either (CallTrace, CheckedException l) a)
+ Control.Monad.Exception.Pure: wrapException :: (Exception e, Throws e' l, Monad m) => (e -> e') -> EMT (Caught e l) m a -> EMT l m a
Files
- Control/Monad/Exception.hs +7/−163
- Control/Monad/Exception/Base.hs +26/−96
- Control/Monad/Exception/Catch.hs +0/−1
- Control/Monad/Exception/IO.hs +229/−0
- Control/Monad/Exception/Pure.hs +221/−0
- changelog +8/−0
- control-monad-exception.cabal +10/−17
Control/Monad/Exception.hs view
@@ -1,171 +1,15 @@-{-# LANGUAGE CPP #-} {-| A Monad Transformer for explicitly typed checked exceptions, described in detail by: - * Jose Iborra, \"Explicitly Typed Exceptions for Haskell",- PADL'10, January 2010, <http://safe-tools.dsic.upv.es/mediawiki/index.php/Jose_Iborra/Papers/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--}--module Control.Monad.Exception (--- * Important trivia--- ** Hierarchies of Exceptions--- $hierarchies---- ** Unchecked exceptions--- *** Unchecked exceptions--- $unchecked---- ** Stack Traces--- $stacktraces---- ** Understanding GHC errors--- $errors---- * The EM monad- EM, tryEM, runEM, runEMParanoid,---- * The EMT monad transformer- EMT(..), CallTrace, tryEMT, runEMT, runEMTParanoid, AnyException, UncaughtException,---- ** The Throws type class- Throws, Caught,---- * Exception primitives- throw, rethrow, Control.Monad.Exception.Base.catch, Control.Monad.Exception.Base.catchWithSrcLoc,- finally, onException, bracket, wrapException,-- showExceptionWithTrace,- FailException(..), MonadZeroException(..), mplusDefault,---- * Reexports- Exception(..), SomeException(..), Typeable(..),- Failure(..),-#if !MIN_VERSION_failure(0,2,0)- Try(..), NothingException(..),- WrapFailure(..),-#endif- MonadLoc(..), withLocTH-) where--import Control.Monad.Exception.Base-import Control.Monad.Exception.Catch-import Control.Failure-import Control.Monad.Loc-import Control.Monad.Loc.TH-import Data.Typeable--{- $hierarchies- 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-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 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)+ * Jose Iborra, \"Explicitly Typed Exceptions for Haskell\",+ PADL'10, January 2010, <http://dl.dropbox.com/s/lgm12trtl0swtra/PADL10.pdf?dl=1> +"Control.Monad.Exception.Pure" provides the classic, Either based monad,+whereas "Control.Monad.Exception.IO" provides a more advanced IO based monad with+the ability to handle asynchronous exceptions as well. -} --{- $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'-> ...+module Control.Monad.Exception ( module Control.Monad.Exception.Pure ) where -is due to an exception handler for @MyException@-missing a type annotation to pin down the type of the exception.--}+import Control.Monad.Exception.Pure
Control/Monad/Exception/Base.hs view
@@ -5,52 +5,15 @@ {-# LANGUAGE MultiParamTypeClasses #-} {-# LANGUAGE PatternGuards #-} {-# LANGUAGE OverlappingInstances #-}--{-|-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--} module Control.Monad.Exception.Base where -import qualified Control.Exception as CE import Control.Applicative+import Control.Arrow+import Control.Monad.Base import Control.Monad.Exception.Catch import Control.Monad.Loc import Control.Monad.Trans.Class+import Control.Monad.Trans.Control import Control.Monad.IO.Class import Control.Failure import Control.Monad.Fix@@ -67,10 +30,10 @@ tryEMT (EMT m) = mapLeft (checkedException.snd) `liftM` m tryEMTWithLoc :: Monad m => EMT AnyException m a -> m (Either (CallTrace, SomeException) a)-tryEMTWithLoc = liftM (mapLeft (\(l,ce) -> (l, checkedException ce))) . unEMT+tryEMTWithLoc = liftM (mapLeft (second checkedException)) . unEMT -runEMT_gen :: forall l m a . Monad m => EMT l m a -> m a-runEMT_gen (EMT m) = m >>= \x ->+runEMTGen :: forall l m a . Monad m => EMT l m a -> m a+runEMTGen (EMT m) = m >>= \x -> case x of Right x -> return x Left (loc,e) -> error (showExceptionWithTrace loc (checkedException e))@@ -83,11 +46,11 @@ -- | Run a safe computation runEMT :: Monad m => EMT NoExceptions m a -> m a-runEMT = runEMT_gen+runEMT = runEMTGen -- | Run a safe computation checking even unchecked ('UncaughtException') exceptions runEMTParanoid :: Monad m => EMT ParanoidMode m a -> m a-runEMTParanoid = runEMT_gen+runEMTParanoid = runEMTGen instance Monad m => Functor (EMT l m) where fmap f emt = EMT $ do@@ -128,10 +91,20 @@ instance MonadTrans (EMT l) where lift = EMT . liftM Right -instance (Exception e, Monad m) => MonadCatch e (EMT (Caught e l) m) (EMT l m) where- catchWithSrcLoc = Control.Monad.Exception.Base.catchWithSrcLoc- catch = Control.Monad.Exception.Base.catch +instance MonadBase b m => MonadBase b (EMT l m) where+ liftBase = liftBaseDefault++instance MonadBaseControl b m => MonadBaseControl b (EMT l m) where+ newtype StM (EMT l m) a = StmEMT {unStmEMT :: ComposeSt (EMT l) m a}+ liftBaseWith = defaultLiftBaseWith StmEMT+ restoreM = defaultRestoreM unStmEMT++instance MonadTransControl (EMT l) where+ newtype StT (EMT l) a = StEMT {unStEMT :: Either (CallTrace, CheckedException l) a}+ liftWith f = EMT $ liftM return $ f $ liftM StEMT . unEMT+ restoreT = EMT . liftM unStEMT+ instance Monad m => MonadLoc (EMT l m) where withLoc loc (EMT emt) = EMT $ do current <- withLoc loc emt@@ -152,49 +125,6 @@ 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.Base.catchWithSrcLoc emt (\_ -> h)---- | Like 'Control.Monad.Exception.Base.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, CheckedException e) -> case fromException e of- Nothing -> return (Left (trace,CheckedException e))- Just e' -> unEMT (h trace e')----- | 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}----- | 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) => (e -> e') -> EMT (Caught e l) m a -> EMT l m a-wrapException mkE m = m `Control.Monad.Exception.Base.catchWithSrcLoc` \loc e -> rethrow loc (mkE e)- showExceptionWithTrace :: Exception e => [String] -> e -> String showExceptionWithTrace [] e = show e showExceptionWithTrace trace e = unlines ( show e@@ -240,6 +170,9 @@ mzero = throw MonadZeroException mplus = mplusDefault +instance (Throws MonadZeroException l) => Alternative (EM l) where+ (<|>) = mplus+ empty = mzero -- ----------- -- Exceptions -- -----------@@ -266,8 +199,5 @@ mapLeft _ (Right x) = Right x -instance (Throws SomeException l, MonadIO m) => MonadIO (EMT l m) where- liftIO m = EMT (liftIO m') where- m' = liftM Right m- `CE.catch`- \(e::SomeException) -> return (Left ([], CheckedException e))+instance MonadIO m => MonadIO (EMT l m) where+ liftIO = lift . liftIO
Control/Monad/Exception/Catch.hs view
@@ -1,6 +1,5 @@ {-# LANGUAGE CPP #-} {-# LANGUAGE UndecidableInstances #-}-{-# LANGUAGE EmptyDataDecls #-} {-# LANGUAGE MultiParamTypeClasses #-} {-# LANGUAGE FunctionalDependencies #-} {-# LANGUAGE FlexibleInstances #-}
+ Control/Monad/Exception/IO.hs view
@@ -0,0 +1,229 @@+{-# 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:++ * Jose Iborra, \"Explicitly Typed Exceptions for Haskell\",+ PADL'10, January 2010, <http://dl.dropbox.com/s/lgm12trtl0swtra/PADL10.pdf?dl=1>++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,++-- * Reexports+ 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 @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 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: 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)
+ Control/Monad/Exception/Pure.hs view
@@ -0,0 +1,221 @@+{-# LANGUAGE CPP #-}++{-|+A Monad Transformer for explicitly typed checked exceptions, described in detail by:++ * Jose Iborra, \"Explicitly Typed Exceptions for Haskell\",+ PADL'10, January 2010, <http://dl.dropbox.com/s/lgm12trtl0swtra/PADL10.pdf?dl=1>++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+-}++module Control.Monad.Exception.Pure (+-- * 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,++-- * Reexports+ Exception(..), SomeException(..), Typeable1,+ 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 (MonadCatch, Exception, SomeException, fromException)+import qualified Control.Monad.Exception.Catch+import Control.Failure+import Data.Typeable++{- $hierarchies+ If your exceptions are hierarchical then you need to+ teach 'Throws' about the hierarchy. See the documentation of+ 'Throws' for more info.+-}+{- $unchecked+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 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: 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, Monad m) => EMT (Caught e l) m a -> (e -> EMT l m a) -> EMT l m a+catch emt h = catchWithSrcLoc emt (const h)++-- | Catch and exception and observe the stack trace.+-- If on top of the IO monad, this will also capture asynchronous exceptions+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, 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, Monad 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 :: 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}+++-- | Like finally, but performs the second computation only when the first one+-- rises an exception+-- TODO asynchronous exceptions! This needs to be moved to Monad+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) => (e -> e') -> EMT (Caught e l) m a -> EMT l m a+wrapException mkE m = m `catchWithSrcLoc` \loc e -> rethrow loc (mkE e)
+ changelog view
@@ -0,0 +1,8 @@+ * 0.9.0 - Moved to transformers (finally leaving the whole mtl-transformers cisma behind)+ * 0.10.0 - removed the dependency on safe-failure+ * 0.10.1 - compatibility with failure 0.2 (thanks to Bas van Dijk)+ * 0.10.2 - use the identity type from mtl (thanks to Bas), require minimum cabal-install version (thanks to Bernhard Urban)+ * 0.10.3 - Moved the MonadIO instance to the main package+ * 0.10.3.1 - Compatibility with base 4.6+ * 0.11 - Experimental support for asynchronous exceptions (via monad-control)+ * 0.11.1 - Add missing Alternative instances
control-monad-exception.cabal view
@@ -1,5 +1,5 @@ name: control-monad-exception-version: 0.10.3.1+version: 0.11.1 Cabal-Version: >= 1.10 build-type: Simple license: PublicDomain@@ -38,7 +38,7 @@ > runEM(eval `catch` \ (e::SomeException) -> return (-1)) :: Expr -> Double . .- In addition to explicitly typed exceptions his package provides:+ In addition to explicitly typed exceptions this package provides: . * Support for explicitly documented, unchecked exceptions (via 'Control.Monad.Exception.tryEMT'). .@@ -61,21 +61,6 @@ > g, Main(example.hs): (2,6) > main, Main(example.hs): (5,9) > main, Main(example.hs): (4,16)- .- /Changes/:- .- . - * 0.9.0 - Moved to transformers (finally leaving the whole mtl-transformers cisma behind)- . - * 0.10.0 - removed the dependency on safe-failure- . - * 0.10.1 - compatibility with failure 0.2 (thanks to Bas van Dijk)- . - * 0.10.2 - use the identity type from mtl (thanks to Bas), require minimum cabal-install version (thanks to Bernhard Urban)- .- * 0.10.3 - Moved the MonadIO instance to the main package- .- * 0.10.3.1 - Compatibility with base 4.6 synopsis: Explicitly typed, checked exceptions with stack traces category: Control, Monads, Failure@@ -83,6 +68,9 @@ tested-with: GHC == 6.12.1 bug-reports: http://github.com/pepeiborra/control-monad-exception/issues +extra-source-files:+ changelog+ Flag extensibleExceptions description: Use extensible-exception package default: False@@ -92,7 +80,10 @@ buildable: True build-depends: failure >= 0.1 && < 0.3 , transformers >= 0.2+ , transformers-base >= 0.4.1 , monadloc >= 0.7+ , monad-control >= 0.3+ , lifted-base >= 0.2.1 if flag(extensibleExceptions) build-depends:@@ -121,6 +112,8 @@ exposed-modules: Control.Monad.Exception+ Control.Monad.Exception.Pure+ Control.Monad.Exception.IO Control.Monad.Exception.Base Control.Monad.Exception.Catch Control.Monad.Exception.Throws