{-# OPTIONS_GHC -XNoImplicitPrelude #-}
-#include "Typeable.h"
-
-----------------------------------------------------------------------------
-- |
-- Module : Control.Exception
module Control.Exception (
-- * The Exception type
+#ifdef __HUGS__
+ SomeException,
+#else
SomeException(..),
- Exception(..), -- instance Eq, Ord, Show, Typeable
- IOException, -- instance Eq, Ord, Show, Typeable
- ArithException(..), -- instance Eq, Ord, Show, Typeable
- ArrayException(..), -- instance Eq, Ord, Show, Typeable
+#endif
+ Exception(..), -- class
+ IOException, -- instance Eq, Ord, Show, Typeable, Exception
+ ArithException(..), -- instance Eq, Ord, Show, Typeable, Exception
+ ArrayException(..), -- instance Eq, Ord, Show, Typeable, Exception
AssertionFailed(..),
- AsyncException(..), -- instance Eq, Ord, Show, Typeable
+ AsyncException(..), -- instance Eq, Ord, Show, Typeable, Exception
-#ifdef __GLASGOW_HASKELL__
- NonTermination(..), nonTermination,
- NestedAtomically(..), nestedAtomically,
+#if __GLASGOW_HASKELL__ || __HUGS__
+ NonTermination(..),
+ NestedAtomically(..),
+#endif
+#ifdef __NHC__
+ System.ExitCode(), -- instance Exception
#endif
BlockedOnDeadMVar(..),
-- ** The @catch@ functions
catch, -- :: IO a -> (Exception -> IO a) -> IO a
-#ifdef __GLASGOW_HASKELL__
catches, Handler(..),
catchJust, -- :: (Exception -> Maybe b) -> IO a -> (b -> IO a) -> IO a
-#endif
-- ** The @handle@ functions
handle, -- :: (Exception -> IO a) -> IO a -> IO a
bracketOnError,
finally, -- :: IO a -> IO b -> IO a
-
-#ifdef __GLASGOW_HASKELL__
- recSelError, recConError, irrefutPatError, runtimeError,
- nonExhaustiveGuardsError, patError, noMethodBindingError,
- assertError,
-#endif
) where
+import Control.Exception.Base
+
#ifdef __GLASGOW_HASKELL__
import GHC.Base
import GHC.IOBase
-import GHC.List
-import GHC.Show
-import GHC.IOBase as ExceptionBase
-import GHC.Exception hiding ( Exception )
-import GHC.Conc
-#endif
-
-#ifdef __HUGS__
-import Hugs.Exception as ExceptionBase
-#endif
-
-import Data.Dynamic
-import Data.Either
import Data.Maybe
-
-#ifdef __NHC__
-import qualified System.IO.Error as H'98 (catch)
-import System.IO.Error (ioError)
-import IO (bracket)
-import DIOError -- defn of IOError type
-import System (ExitCode())
-import System.IO.Unsafe (unsafePerformIO)
-import Unsafe.Coerce (unsafeCoerce)
-
--- minimum needed for nhc98 to pretend it has Exceptions
-
-{-
-data Exception = IOException IOException
- | ArithException ArithException
- | ArrayException ArrayException
- | AsyncException AsyncException
- | ExitException ExitCode
- deriving Show
--}
-class ({-Typeable e,-} Show e) => Exception e where
- toException :: e -> SomeException
- fromException :: SomeException -> Maybe e
-
-data SomeException = forall e . Exception e => SomeException e
-
-INSTANCE_TYPEABLE0(SomeException,someExceptionTc,"SomeException")
-
-instance Show SomeException where
- showsPrec p (SomeException e) = showsPrec p e
-instance Exception SomeException where
- toException se = se
- fromException = Just
-
-type IOException = IOError
-instance Exception IOError where
- toException = SomeException
- fromException (SomeException e) = Just (unsafeCoerce e)
-
-instance Exception ExitCode where
- toException = SomeException
- fromException (SomeException e) = Just (unsafeCoerce e)
-
-data ArithException
-data ArrayException
-data AsyncException
-data AssertionFailed
-data PatternMatchFail
-data NoMethodError
-data Deadlock
-data BlockedOnDeadMVar
-data BlockedIndefinitely
-data ErrorCall
-data RecConError
-data RecSelError
-data RecUpdError
-instance Show ArithException
-instance Show ArrayException
-instance Show AsyncException
-instance Show AssertionFailed
-instance Show PatternMatchFail
-instance Show NoMethodError
-instance Show Deadlock
-instance Show BlockedOnDeadMVar
-instance Show BlockedIndefinitely
-instance Show ErrorCall
-instance Show RecConError
-instance Show RecSelError
-instance Show RecUpdError
-
-catch :: Exception e
- => IO a -- ^ The computation to run
- -> (e -> IO a) -- ^ Handler to invoke if an exception is raised
- -> IO a
-catch io h = H'98.catch io (h . fromJust . fromException . toException)
-
-throwIO :: Exception e => e -> IO a
-throwIO = ioError . fromJust . fromException . toException
-
-throw :: Exception e => e -> a
-throw = unsafePerformIO . throwIO
-
-evaluate :: a -> IO a
-evaluate x = x `seq` return x
-
-assert :: Bool -> a -> a
-assert True x = x
-assert False _ = throw (toException (UserError "" "Assertion failed"))
-
+#else
+import Prelude hiding (catch)
#endif
-#ifndef __GLASGOW_HASKELL__
--- Dummy definitions for implementations lacking asynchonous exceptions
-
-block :: IO a -> IO a
-block = id
-unblock :: IO a -> IO a
-unblock = id
-blocked :: IO Bool
-blocked = return False
+#ifdef __NHC__
+import System (ExitCode())
#endif
------------------------------------------------------------------------------
--- Catching exceptions
-
--- |This is the simplest of the exception-catching functions. It
--- takes a single argument, runs it, and if an exception is raised
--- the \"handler\" is executed, with the value of the exception passed as an
--- argument. Otherwise, the result is returned as normal. For example:
---
--- > catch (openFile f ReadMode)
--- > (\e -> hPutStr stderr ("Couldn't open "++f++": " ++ show e))
---
--- For catching exceptions in pure (non-'IO') expressions, see the
--- function 'evaluate'.
---
--- Note that due to Haskell\'s unspecified evaluation order, an
--- expression may return one of several possible exceptions: consider
--- the expression @error \"urk\" + 1 \`div\` 0@. Does
--- 'catch' execute the handler passing
--- @ErrorCall \"urk\"@, or @ArithError DivideByZero@?
---
--- The answer is \"either\": 'catch' makes a
--- non-deterministic choice about which exception to catch. If you
--- call it again, you might get a different exception back. This is
--- ok, because 'catch' is an 'IO' computation.
---
--- Note that 'catch' catches all types of exceptions, and is generally
--- used for \"cleaning up\" before passing on the exception using
--- 'throwIO'. It is not good practice to discard the exception and
--- continue, without first checking the type of the exception (it
--- might be a 'ThreadKilled', for example). In this case it is usually better
--- to use 'catchJust' and select the kinds of exceptions to catch.
---
--- Also note that the "Prelude" also exports a function called
--- 'Prelude.catch' with a similar type to 'Control.Exception.catch',
--- except that the "Prelude" version only catches the IO and user
--- families of exceptions (as required by Haskell 98).
---
--- We recommend either hiding the "Prelude" version of 'Prelude.catch'
--- when importing "Control.Exception":
---
--- > import Prelude hiding (catch)
---
--- or importing "Control.Exception" qualified, to avoid name-clashes:
---
--- > import qualified Control.Exception as C
---
--- and then using @C.catch@
---
-#ifndef __NHC__
-catch :: Exception e
- => IO a -- ^ The computation to run
- -> (e -> IO a) -- ^ Handler to invoke if an exception is raised
- -> IO a
-catch = ExceptionBase.catchException
-#endif
+data Handler a = forall e . Exception e => Handler (e -> IO a)
catches :: IO a -> [Handler a] -> IO a
catches io handlers = io `catch` catchesHandler handlers
Just e' -> handler e'
Nothing -> res
-data Handler a = forall e . Exception e => Handler (e -> IO a)
--- | The function 'catchJust' is like 'catch', but it takes an extra
--- argument which is an /exception predicate/, a function which
--- selects which type of exceptions we\'re interested in.
---
--- > result <- catchJust errorCalls thing_to_try handler
---
--- Any other exceptions which are not matched by the predicate
--- are re-raised, and may be caught by an enclosing
--- 'catch' or 'catchJust'.
-catchJust
- :: Exception e
- => (e -> Maybe b) -- ^ Predicate to select exceptions
- -> IO a -- ^ Computation to run
- -> (b -> IO a) -- ^ Handler
- -> IO a
-catchJust p a handler = catch a handler'
- where handler' e = case p e of
- Nothing -> throw e
- Just b -> handler b
-
--- | A version of 'catch' with the arguments swapped around; useful in
--- situations where the code for the handler is shorter. For example:
---
--- > do handle (\e -> exitWith (ExitFailure 1)) $
--- > ...
-handle :: Exception e => (e -> IO a) -> IO a -> IO a
-handle = flip catch
-
--- | A version of 'catchJust' with the arguments swapped around (see
--- 'handle').
-handleJust :: Exception e => (e -> Maybe b) -> (b -> IO a) -> IO a -> IO a
-handleJust p = flip (catchJust p)
-
------------------------------------------------------------------------------
--- 'mapException'
-
--- | This function maps one exception into another as proposed in the
--- paper \"A semantics for imprecise exceptions\".
-
--- Notice that the usage of 'unsafePerformIO' is safe here.
-
-mapException :: (Exception e1, Exception e2) => (e1 -> e2) -> a -> a
-mapException f v = unsafePerformIO (catch (evaluate v)
- (\x -> throw (f x)))
-
------------------------------------------------------------------------------
--- 'try' and variations.
-
--- | Similar to 'catch', but returns an 'Either' result which is
--- @('Right' a)@ if no exception was raised, or @('Left' e)@ if an
--- exception was raised and its value is @e@.
---
--- > try a = catch (Right `liftM` a) (return . Left)
---
--- Note: as with 'catch', it is only polite to use this variant if you intend
--- to re-throw the exception after performing whatever cleanup is needed.
--- Otherwise, 'tryJust' is generally considered to be better.
---
--- Also note that "System.IO.Error" also exports a function called
--- 'System.IO.Error.try' with a similar type to 'Control.Exception.try',
--- except that it catches only the IO and user families of exceptions
--- (as required by the Haskell 98 @IO@ module).
-
-try :: Exception e => IO a -> IO (Either e a)
-try a = catch (a >>= \ v -> return (Right v)) (\e -> return (Left e))
-
--- | A variant of 'try' that takes an exception predicate to select
--- which exceptions are caught (c.f. 'catchJust'). If the exception
--- does not match the predicate, it is re-thrown.
-tryJust :: Exception e => (e -> Maybe b) -> IO a -> IO (Either b a)
-tryJust p a = do
- r <- try a
- case r of
- Right v -> return (Right v)
- Left e -> case p e of
- Nothing -> throw e
- Just b -> return (Left b)
-
-onException :: IO a -> IO b -> IO a
-onException io what = io `catch` \e -> do what
- throw (e :: SomeException)
-
------------------------------------------------------------------------------
--- Some Useful Functions
-
--- | When you want to acquire a resource, do some work with it, and
--- then release the resource, it is a good idea to use 'bracket',
--- because 'bracket' will install the necessary exception handler to
--- release the resource in the event that an exception is raised
--- during the computation. If an exception is raised, then 'bracket' will
--- re-raise the exception (after performing the release).
---
--- A common example is opening a file:
---
--- > bracket
--- > (openFile "filename" ReadMode)
--- > (hClose)
--- > (\handle -> do { ... })
---
--- The arguments to 'bracket' are in this order so that we can partially apply
--- it, e.g.:
---
--- > withFile name mode = bracket (openFile name mode) hClose
---
-#ifndef __NHC__
-bracket
- :: IO a -- ^ computation to run first (\"acquire resource\")
- -> (a -> IO b) -- ^ computation to run last (\"release resource\")
- -> (a -> IO c) -- ^ computation to run in-between
- -> IO c -- returns the value from the in-between computation
-bracket before after thing =
- block (do
- a <- before
- r <- unblock (thing a) `onException` after a
- after a
- return r
- )
-#endif
-
--- | A specialised variant of 'bracket' with just a computation to run
--- afterward.
---
-finally :: IO a -- ^ computation to run first
- -> IO b -- ^ computation to run afterward (even if an exception
- -- was raised)
- -> IO a -- returns the value from the first computation
-a `finally` sequel =
- block (do
- r <- unblock a `onException` sequel
- sequel
- return r
- )
-
--- | A variant of 'bracket' where the return value from the first computation
--- is not required.
-bracket_ :: IO a -> IO b -> IO c -> IO c
-bracket_ before after thing = bracket before (const after) (const thing)
-
--- | Like bracket, but only performs the final action if there was an
--- exception raised by the in-between computation.
-bracketOnError
- :: IO a -- ^ computation to run first (\"acquire resource\")
- -> (a -> IO b) -- ^ computation to run last (\"release resource\")
- -> (a -> IO c) -- ^ computation to run in-between
- -> IO c -- returns the value from the in-between computation
-bracketOnError before after thing =
- block (do
- a <- before
- unblock (thing a) `onException` after a
- )
-
-- -----------------------------------------------------------------------------
-- Asynchronous exceptions
Similar arguments apply for other interruptible operations like
'System.IO.openFile'.
-}
-
-#if !(__GLASGOW_HASKELL__ || __NHC__)
-assert :: Bool -> a -> a
-assert True x = x
-assert False _ = throw (AssertionFailed "")
-#endif
-
-#ifndef __NHC__
-recSelError, recConError, irrefutPatError, runtimeError,
- nonExhaustiveGuardsError, patError, noMethodBindingError
- :: Addr# -> a -- All take a UTF8-encoded C string
-
-recSelError s = throw (RecSelError (unpackCStringUtf8# s)) -- No location info unfortunately
-runtimeError s = error (unpackCStringUtf8# s) -- No location info unfortunately
-
-nonExhaustiveGuardsError s = throw (PatternMatchFail (untangle s "Non-exhaustive guards in"))
-irrefutPatError s = throw (PatternMatchFail (untangle s "Irrefutable pattern failed for pattern"))
-recConError s = throw (RecConError (untangle s "Missing field in record construction"))
-noMethodBindingError s = throw (NoMethodError (untangle s "No instance nor default method for class operation"))
-patError s = throw (PatternMatchFail (untangle s "Non-exhaustive patterns in"))
-
------
-
-data PatternMatchFail = PatternMatchFail String
-INSTANCE_TYPEABLE0(PatternMatchFail,patternMatchFailTc,"PatternMatchFail")
-
-instance Exception PatternMatchFail
-
-instance Show PatternMatchFail where
- showsPrec _ (PatternMatchFail err) = showString err
-
------
-
-data RecSelError = RecSelError String
-INSTANCE_TYPEABLE0(RecSelError,recSelErrorTc,"RecSelError")
-
-instance Exception RecSelError
-
-instance Show RecSelError where
- showsPrec _ (RecSelError err) = showString err
-
------
-
-data RecConError = RecConError String
-INSTANCE_TYPEABLE0(RecConError,recConErrorTc,"RecConError")
-
-instance Exception RecConError
-
-instance Show RecConError where
- showsPrec _ (RecConError err) = showString err
-
------
-
-data RecUpdError = RecUpdError String
-INSTANCE_TYPEABLE0(RecUpdError,recUpdErrorTc,"RecUpdError")
-
-instance Exception RecUpdError
-
-instance Show RecUpdError where
- showsPrec _ (RecUpdError err) = showString err
-
------
-
-data NoMethodError = NoMethodError String
-INSTANCE_TYPEABLE0(NoMethodError,noMethodErrorTc,"NoMethodError")
-
-instance Exception NoMethodError
-
-instance Show NoMethodError where
- showsPrec _ (NoMethodError err) = showString err
-
------
-
-data NonTermination = NonTermination
-INSTANCE_TYPEABLE0(NonTermination,nonTerminationTc,"NonTermination")
-
-instance Exception NonTermination
-
-instance Show NonTermination where
- showsPrec _ NonTermination = showString "<<loop>>"
-
--- GHC's RTS calls this
-nonTermination :: SomeException
-nonTermination = toException NonTermination
-
------
-
-data NestedAtomically = NestedAtomically
-INSTANCE_TYPEABLE0(NestedAtomically,nestedAtomicallyTc,"NestedAtomically")
-
-instance Exception NestedAtomically
-
-instance Show NestedAtomically where
- showsPrec _ NestedAtomically = showString "Control.Concurrent.STM.atomically was nested"
-
--- GHC's RTS calls this
-nestedAtomically :: SomeException
-nestedAtomically = toException NestedAtomically
-
------
-
-instance Exception Dynamic
-
-#endif
-