packages feed

control-monad-exception 0.4.5 → 0.4.6

raw patch · 4 files changed

+231/−72 lines, 4 files

Files

Control/Monad/Exception.hs view
@@ -6,27 +6,127 @@ {-# LANGUAGE TemplateHaskell #-} {-# LANGUAGE NamedFieldPuns #-} +{-|+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++/Notes about type errors and exception hierarchies/++ * 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.++ * 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+++ * 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.++>       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)+++-} module Control.Monad.Exception (-    EM,  evalEM, runEM, runEMParanoid,-    EMT, evalEMT, runEMT, runEMTParanoid,-    WithSrcLoc(..), withLocTH, showExceptionWithTrace,+    EM,  tryEM, runEM, runEMParanoid,+    EMT, tryEMT, runEMT, runEMTParanoid,+    WithSrcLoc(..), withLocTH,     MonadZeroException(..),     module Control.Monad.Exception.Class ) where  import Control.Applicative import Control.Monad.Identity import Control.Monad.Exception.Class-import Control.Monad.Fix import Control.Monad.Trans import Control.Monad.Cont.Class import Control.Monad.RWS.Class import Data.Monoid import Data.Typeable-import qualified Language.Haskell.TH.Syntax import Language.Haskell.TH.Syntax hiding (lift)-import Prelude hiding (catch) import Text.PrettyPrint+import Prelude hiding (catch) +-- | A monad of explicitly typed, checked exceptions type EM l = EMT l Identity  @@ -35,14 +135,14 @@ mapLeft _ (Right x) = Right x  -- | Run a computation explicitly handling exceptions-evalEM :: EM (AnyException l) a -> Either SomeException a-evalEM = runIdentity . evalEMT+tryEM :: EM (AnyException l) a -> Either SomeException a+tryEM = runIdentity . tryEMT  -- | Run a safe computation runEM :: EM NoExceptions a -> a runEM = runIdentity . runEMT --- | Run a safe computation checking even unchecked (@UncaughtExceptions@) exceptions+-- | Run a computation checking even unchecked (@UncaughtExceptions@) exceptions runEMParanoid :: EM ParanoidMode a -> a runEMParanoid = runIdentity . runEMTParanoid @@ -53,19 +153,14 @@  type AnyException = Caught SomeException --- | Run explicitly handling exceptions-evalEMT :: Monad m => EMT (AnyException l) m a -> m (Either SomeException a)-evalEMT (EMT m) = mapLeft (wrapException.snd) `liftM` m+-- | 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  runEMT_gen :: Monad m => EMT l m a -> m a runEMT_gen (EMT m) = liftM f m where   f (Right x) = x-  f (Left  e) = error (uncurry showExceptionWithTrace e)--showExceptionWithTrace :: Show e => [String] -> e -> String-showExceptionWithTrace trace e = render$-             text (show e) $$-             text " in" <+> (vcat (map text $ reverse trace))+  f (Left (loc,e)) = error (showExceptionWithTrace loc (unwrapException e))  -- | Run a safe computation runEMT :: Monad m => EMT NoExceptions m a -> m a@@ -129,7 +224,6 @@   --   when used to wrap a EMT computation.   --   --   On any other monad or value, 'withLoc' is defined as the identity-  -- | hello   withLoc :: String -> a -> a  instance WithSrcLoc a where withLoc _ = id
Control/Monad/Exception/Class.hs view
@@ -5,14 +5,19 @@ {-# 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(..),-       Throws, Caught,        WrapException(..), Exception(..), SomeException(..),-       UncaughtException, NoExceptions, ParanoidMode+       showExceptionWithTrace        ) where  import Control.Monad@@ -40,29 +45,12 @@ import Control.Exception (Exception(..), SomeException) import qualified Control.Exception #endif-import Data.Monoid import Data.Typeable-import Prelude hiding (catch)----- Closing a type class with an unexported constraint---  @Private@  is unexported-class Private l-instance Private (Caught e l)--{-| @Throws@ is the mechanism used to keep a type level-    list of exceptions.--    Usually there is no need for the user of this library-    to add further instances to @Throws@ except in one-    case: to encode subtyping. For instance if we have-    an @IOException@ type and a @FIleNotFoundException@ subcase,-    we need to add the instance:+import Text.PrettyPrint - > instance Throws FileNotFoundException (Caught IOException l)+import Control.Monad.Exception.Throws --}-class (Private l, Exception e) => Throws e l --  | e -> l+import Prelude hiding (catch)  class Monad m => MonadThrow e m where     throw :: e -> m a@@ -80,35 +68,23 @@ instance Exception e => MonadCatch e IO IO where    catch   = Control.Exception.catch ---- | A type level witness of a exception handler.-data Caught e l--instance Exception e => Throws e (Caught e l)-instance Throws e l  => Throws e (Caught e' l)---- | @SomeException@ is at the top of the exception hierarchy---   .---   Capturing SomeException captures every possible exception-instance Exception e => Throws e (Caught SomeException l)--data NoExceptions-instance Private NoExceptions+{-| Given a list of source locations and an exception, @showExceptionWithTrace@ produces output of the form -data ParanoidMode-instance Private ParanoidMode+>       <exception details>+>        in <module a>(<file a.hs>): (12,6)+>           <module b>(<file b.hs>): (11,7)+>           ... --- | Uncaught Exceptions model unchecked exceptions (a la RuntimeException in Java)------   In order to declare an unchecked exception @e@,---   all that is needed is to make @e@ an instance of @UncaughtException@-class Exception e => UncaughtException e-instance UncaughtException e => Throws e NoExceptions+-}+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 {wrapException::SomeException} deriving (Typeable)+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
+ Control/Monad/Exception/Throws.hs view
@@ -0,0 +1,84 @@+{-# LANGUAGE CPP #-}+{-# LANGUAGE EmptyDataDecls #-}+{-# LANGUAGE MultiParamTypeClasses #-}+{-# LANGUAGE OverlappingInstances, FlexibleInstances #-}++{-|+Defines the @Throws@ binary relationship between types.+-}++module Control.Monad.Exception.Throws (Throws, Caught, UncaughtException, NoExceptions, ParanoidMode) where++#if __GLASGOW_HASKELL__ < 610+import Control.Exception.Extensible (Exception(..), SomeException)+#else+import Control.Exception (Exception(..), SomeException)+#endif+++-- | A type level witness of a exception handler.+data Caught e l+++-- Closing a type class with an unexported constraint+--  @Private@  is unexported+class Private l+instance Private (Caught e l)++{-| @Throws@ is a type level binary relationship+    used to model a list of exceptions.++    Usually there is no need for the user+    to add further instances to @Throws@ except+    to encode 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   TopException   --         |+>                                                 --   MidException+>   instance Throws ChildException MidException   --         |+>   instance Throws ChildException TopException   --         |+>                                                 --  ChildException++'SomeException' is automatically+   an ancestor of every other exception type.+++-}++class (Private l, Exception e) => Throws e l++instance Throws e l  => Throws e (Caught e' l)+instance Exception e => Throws e (Caught e l)++-- | @SomeException@ is at the top of the exception hierarchy+--   .+--   Capturing SomeException captures every possible exception+instance Exception e => Throws e (Caught SomeException l)++-- | Uncaught Exceptions model unchecked exceptions (a la RuntimeException in Java)+--+--   In order to declare an unchecked exception @e@,+--   all that is needed is to make @e@ an instance of @UncaughtException@+class Exception e => UncaughtException e+instance UncaughtException e => Throws e NoExceptions+++data NoExceptions+instance Private NoExceptions++data ParanoidMode+instance Private ParanoidMode
control-monad-exception.cabal view
@@ -1,5 +1,5 @@ name: control-monad-exception-version: 0.4.5+version: 0.4.6 Cabal-Version:  >= 1.2.3 build-type: Simple license: PublicDomain@@ -8,7 +8,9 @@ homepage: http://safe-tools.dsic.upv.es/mediawiki/index.php/Jose_Iborra/Papers/Exceptions description:    This package provides explicitly typed, checked exceptions as a library.-+  .+  Computations throwing different types of exception can be combined seamlessly.+  .   /Example/   .   > data Expr = Add Expr Expr | Div Expr Expr | Val Double@@ -35,20 +37,22 @@   > eval `catch` \ (e::DivideByZero) -> return (-1)  :: Throws SumOverflow l => Expr -> EM l Double   > runEM(eval `catch` \ (e::SomeException) -> return (-1))  :: Expr -> Double   .-  New in version 0.4:   .-    * Support for unchecked exceptions (with 'UncaughtException')+  This package provides, among other things:   .-    * Support for exception stack traces (with 'WithSrcLoc'). /Example/+    * Support for explicitly documented, unchecked exceptions (with 'tryEM').   .+    * Support for selective unchecked exceptions (with 'UncaughtException').+  .+    * Support for exception stack traces (experimental). /Example:/+  .   >       f () = $withLocTH $ throw MyException   >       g a  = $withLocTH $ f a   >   >       main = runEMT $ $withLocTH $ do-  >       g () `catchWithSrcLoc` \loc MyException ->-  >              lift $ putStrLn (showExceptionWithTrace loc MyException)+  >       g () `catchWithSrcLoc` \loc (e::MyException) -> lift(putStrLn$ showExceptionWithTrace loc e)   .-  > -- Running main produces the output:+  >        -- Running main produces the output:   .   >       *Main> main   >       MyException@@ -98,5 +102,6 @@   build-depends: pretty, template-haskell   exposed-modules:      Control.Monad.Exception.Class+     Control.Monad.Exception.Throws      Control.Monad.Exception   ghc-options: -Wall -fno-warn-name-shadowing