Exception.hs 2.36 KB
Newer Older
1 2 3

module Exception
    (
4 5 6 7 8 9 10 11
    module Control.Exception,
    module Exception
    )
    where

import Prelude hiding (catch)

#if __GLASGOW_HASKELL__ < 609
12 13 14
import Control.Exception.Extensible as Control.Exception
#else
import Control.Exception
15 16 17 18
#endif

catchIO :: IO a -> (IOException -> IO a) -> IO a
catchIO = catch
19

20 21
handleIO :: (IOException -> IO a) -> IO a -> IO a
handleIO = flip catchIO
22

23 24
tryIO :: IO a -> IO (Either IOException a)
tryIO = try
25

26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76
-- | A monad that can catch exceptions.  A minimal definition
-- requires a definition of 'gcatch'.
--
-- Although, 'gbracket' and 'gfinally' could be modelled on top of 'gcatch',
-- they are included in the type class since GHC needs special implementations
-- of these in order to properly handle asynchronous exceptions.
class Monad m => ExceptionMonad m where
  -- | Generalised version of 'Control.Exception.catch', allowing an arbitrary
  -- exception handling monad instead of just 'IO'.
  gcatch :: Exception e => m a -> (e -> m a) -> m a

  -- | Generalised version of 'Control.Exception.bracket', allowing an arbitrary
  -- exception handling monad instead of just 'IO'.
  gbracket :: m a -> (a -> m b) -> (a -> m c) -> m c

  -- | Generalised version of 'Control.Exception.finally', allowing an arbitrary
  -- exception handling monad instead of just 'IO'.
  gfinally :: m a -> m b -> m a

  gbracket acquire release in_between = do
      a <- acquire
      r <- in_between a `gonException` release a
      release a
      return r

  gfinally thing cleanup = do
      r <- thing `gonException` cleanup
      cleanup
      return r

instance ExceptionMonad IO where
  gcatch    = catch
  gbracket  = bracket
  gfinally  = finally


gtry :: (ExceptionMonad m, Exception e) => m a -> m (Either e a)
gtry act = gcatch (act >>= \a -> return (Right a))
                  (\e -> return (Left e))

-- | Generalised version of 'Control.Exception.handle', allowing an arbitrary
-- exception handling monad instead of just 'IO'.
ghandle :: (ExceptionMonad m, Exception e) => (e -> m a) -> m a -> m a
ghandle = flip gcatch

-- | Always executes the first argument.  If this throws an exception the
-- second argument is executed and the exception is raised again.
gonException :: (ExceptionMonad m) => m a -> m b -> m a
gonException ioA cleanup = ioA `gcatch` \e ->
                             do cleanup
                                throw (e :: SomeException)
77