AsyncException(..), -- instance Eq, Ord, Show, Typeable
-- * Throwing exceptions
+ throwIO, -- :: Exception -> IO a
throw, -- :: Exception -> a
- ioError, -- :: Exception -> IO a
+ ioError, -- :: IOError -> IO a
+#ifdef __GLASGOW_HASKELL__
throwTo, -- :: ThreadId -> Exception -> a
+#endif
-- * Catching Exceptions
-- ** The @evaluate@ function
evaluate, -- :: a -> IO a
+ -- ** The @mapException@ function
+ mapException, -- :: (Exception -> Exception) -> a -> a
+
-- ** Exception predicates
-- $preds
-- $dynamic
throwDyn, -- :: Typeable ex => ex -> b
+#ifdef __GLASGOW_HASKELL__
throwDynTo, -- :: Typeable ex => ThreadId -> ex -> b
+#endif
catchDyn, -- :: Typeable ex => IO a -> (ex -> IO a) -> IO a
-- * Asynchronous Exceptions
bracket, -- :: IO a -> (a -> IO b) -> (a -> IO c) -> IO ()
bracket_, -- :: IO a -> IO b -> IO c -> IO ()
- finally, -- :: IO a -> IO b -> IO b
+ finally, -- :: IO a -> IO b -> IO a
) where
#ifdef __GLASGOW_HASKELL__
-import Prelude hiding (catch)
-import System.IO.Error
import GHC.Base ( assert )
-import GHC.Exception hiding (try, catch, bracket, bracket_)
+import GHC.Exception as ExceptionBase hiding (catch)
import GHC.Conc ( throwTo, ThreadId )
import GHC.IOBase ( IO(..) )
#endif
#ifdef __HUGS__
-import Prelude hiding ( catch )
-import PrelPrim ( catchException
- , Exception(..)
- , throw
- , ArithException(..)
- , AsyncException(..)
- , assert
- )
+import Hugs.Exception as ExceptionBase
#endif
+import Prelude hiding ( catch )
+import System.IO.Error hiding ( catch, try )
+import System.IO.Unsafe (unsafePerformIO)
import Data.Dynamic
-#include "Dynamic.h"
+#include "Typeable.h"
INSTANCE_TYPEABLE0(Exception,exceptionTc,"Exception")
INSTANCE_TYPEABLE0(IOException,ioExceptionTc,"IOException")
INSTANCE_TYPEABLE0(ArithException,arithExceptionTc,"ArithException")
--
-- Note that 'catch' catches all types of exceptions, and is generally
-- used for \"cleaning up\" before passing on the exception using
--- 'ioError'. It is not good practice to discard the exception and
+-- '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 'catch' which has the same type as
--- 'Exception.catch', the difference being that the
+-- 'Control.Exception.catch', the difference being 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
catch :: IO a -- ^ The computation to run
-> (Exception -> IO a) -- ^ Handler to invoke if an exception is raised
-> IO a
-catch = GHC.Exception.catchException
+catch = ExceptionBase.catchException
-- | The function 'catchJust' is like 'catch', but it takes an extra
-- argument which is an /exception predicate/, a function which
-- > catch (evaluate undefined) (\e -> return ()) ==> return ()
--
-- NOTE: @(evaluate a)@ is /not/ the same as @(a \`seq\` return a)@.
+#ifdef __GLASGOW_HASKELL__
evaluate :: a -> IO a
evaluate a = IO $ \s -> case a `seq` () of () -> (# s, a #)
-- NB. can't write
-- a `seq` (# s, a #)
-- because we can't have an unboxed tuple as a function argument
+#endif
+
+-----------------------------------------------------------------------------
+-- '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 -> Exception) -> a -> a
+mapException f v = unsafePerformIO (catch (evaluate v)
+ (\x -> throw (f x)))
-----------------------------------------------------------------------------
-- 'try' and variations.
-- Dynamic exceptions
-- $dynamic
--- Because the 'Exception' datatype is not extensible, there is an
+-- #DynamicExceptions# Because the 'Exception' datatype is not extensible, there is an
-- interface for throwing and catching exceptions of type 'Dynamic'
-- (see "Data.Dynamic") which allows exception values of any type in
-- the 'Typeable' class to be thrown and caught.
throwDyn :: Typeable exception => exception -> b
throwDyn exception = throw (DynException (toDyn exception))
+#ifdef __GLASGOW_HASKELL__
-- | A variant of 'throwDyn' that throws the dynamic exception to an
--- arbitrary thread (c.f. 'throwTo').
+-- arbitrary thread (GHC only: c.f. 'throwTo').
throwDynTo :: Typeable exception => ThreadId -> exception -> IO ()
throwDynTo t exception = throwTo t (DynException (toDyn exception))
+#endif /* __GLASGOW_HASKELL__ */
-- | Catch dynamic exceptions of the required type. All other
-- exceptions are re-thrown, including dynamic exceptions of the wrong
ioErrors :: Exception -> Maybe IOError
arithExceptions :: Exception -> Maybe ArithException
errorCalls :: Exception -> Maybe String
-dynExceptions :: Exception -> Maybe Dynamic
assertions :: Exception -> Maybe String
+dynExceptions :: Exception -> Maybe Dynamic
asyncExceptions :: Exception -> Maybe AsyncException
userErrors :: Exception -> Maybe String
-ioErrors e@(IOException _) = Just e
+ioErrors (IOException e) = Just e
ioErrors _ = Nothing
arithExceptions (ArithException e) = Just e
asyncExceptions (AsyncException e) = Just e
asyncExceptions _ = Nothing
-userErrors e | isUserError e = Just (ioeGetErrorString e)
+userErrors (IOException e) | isUserError e = Just (ioeGetErrorString e)
userErrors _ = Nothing
-----------------------------------------------------------------------------
{- $async
-Asynchronous exceptions are so-called because they arise due to
+ #AsynchronousExceptions# Asynchronous exceptions are so-called because they arise due to
external influences, and can be raised at any point during execution.
'StackOverflow' and 'HeapOverflow' are two examples of
system-generated asynchronous exceptions.
> throwTo :: ThreadId -> Exception -> IO ()
-'throwTo' (also 'throwDynTo' and 'Concurrent.killThread') allows one
+'throwTo' (also 'throwDynTo' and 'Control.Concurrent.killThread') allows one
running thread to raise an arbitrary exception in another thread. The
exception is therefore asynchronous with respect to the target thread,
which could be doing anything at the time it receives the exception.
safe in the knowledge that the thread can receive exceptions right up
until the point when the 'takeMVar' succeeds.
Similar arguments apply for other interruptible operations like
-'IO.openFile'.
+'GHC.Handle.openFile'.
-}
-- -----------------------------------------------------------------------------
-- returned as the result.
assert :: Bool -> a -> a
#endif
+
+#ifndef __GLASGOW_HASKELL__
+assert :: Bool -> a -> a
+assert True x = x
+assert False _ = throw (AssertionFailed "")
+#endif