module Control.Exception (
- -- * The Exception type
- Exception(..), -- instance Eq, Ord, Show, Typeable
- IOException, -- instance Eq, Ord, Show, Typeable
- ArithException(..), -- instance Eq, Ord, Show, Typeable
- ArrayException(..), -- instance Eq, Ord, Show, Typeable
- AsyncException(..), -- instance Eq, Ord, Show, Typeable
-
- -- * Throwing exceptions
- throwIO, -- :: Exception -> IO a
- throw, -- :: Exception -> a
- ioError, -- :: IOError -> IO a
+ -- * The Exception type
+ Exception(..), -- instance Eq, Ord, Show, Typeable
+ IOException, -- instance Eq, Ord, Show, Typeable
+ ArithException(..), -- instance Eq, Ord, Show, Typeable
+ ArrayException(..), -- instance Eq, Ord, Show, Typeable
+ AsyncException(..), -- instance Eq, Ord, Show, Typeable
+
+ -- * Throwing exceptions
+ throwIO, -- :: Exception -> IO a
+ throw, -- :: Exception -> a
+ ioError, -- :: IOError -> IO a
#ifdef __GLASGOW_HASKELL__
- throwTo, -- :: ThreadId -> Exception -> a
+ throwTo, -- :: ThreadId -> Exception -> a
#endif
- -- * Catching Exceptions
+ -- * Catching Exceptions
- -- |There are several functions for catching and examining
- -- exceptions; all of them may only be used from within the
- -- 'IO' monad.
+ -- |There are several functions for catching and examining
+ -- exceptions; all of them may only be used from within the
+ -- 'IO' monad.
- -- ** The @catch@ functions
- catch, -- :: IO a -> (Exception -> IO a) -> IO a
- catchJust, -- :: (Exception -> Maybe b) -> IO a -> (b -> IO a) -> IO a
+ -- ** The @catch@ functions
+ catch, -- :: IO a -> (Exception -> IO a) -> IO a
+ catchJust, -- :: (Exception -> Maybe b) -> IO a -> (b -> IO a) -> IO a
- -- ** The @handle@ functions
- handle, -- :: (Exception -> IO a) -> IO a -> IO a
- handleJust,-- :: (Exception -> Maybe b) -> (b -> IO a) -> IO a -> IO a
+ -- ** The @handle@ functions
+ handle, -- :: (Exception -> IO a) -> IO a -> IO a
+ handleJust,-- :: (Exception -> Maybe b) -> (b -> IO a) -> IO a -> IO a
- -- ** The @try@ functions
- try, -- :: IO a -> IO (Either Exception a)
- tryJust, -- :: (Exception -> Maybe b) -> a -> IO (Either b a)
+ -- ** The @try@ functions
+ try, -- :: IO a -> IO (Either Exception a)
+ tryJust, -- :: (Exception -> Maybe b) -> a -> IO (Either b a)
- -- ** The @evaluate@ function
- evaluate, -- :: a -> IO a
+ -- ** The @evaluate@ function
+ evaluate, -- :: a -> IO a
- -- ** The @mapException@ function
- mapException, -- :: (Exception -> Exception) -> a -> a
+ -- ** The @mapException@ function
+ mapException, -- :: (Exception -> Exception) -> a -> a
- -- ** Exception predicates
-
- -- $preds
+ -- ** Exception predicates
+
+ -- $preds
- ioErrors, -- :: Exception -> Maybe IOError
- arithExceptions, -- :: Exception -> Maybe ArithException
- errorCalls, -- :: Exception -> Maybe String
- dynExceptions, -- :: Exception -> Maybe Dynamic
- assertions, -- :: Exception -> Maybe String
- asyncExceptions, -- :: Exception -> Maybe AsyncException
- userErrors, -- :: Exception -> Maybe String
+ ioErrors, -- :: Exception -> Maybe IOError
+ arithExceptions, -- :: Exception -> Maybe ArithException
+ errorCalls, -- :: Exception -> Maybe String
+ dynExceptions, -- :: Exception -> Maybe Dynamic
+ assertions, -- :: Exception -> Maybe String
+ asyncExceptions, -- :: Exception -> Maybe AsyncException
+ userErrors, -- :: Exception -> Maybe String
- -- * Dynamic exceptions
+ -- * Dynamic exceptions
- -- $dynamic
- throwDyn, -- :: Typeable ex => ex -> b
+ -- $dynamic
+ throwDyn, -- :: Typeable ex => ex -> b
#ifdef __GLASGOW_HASKELL__
- throwDynTo, -- :: Typeable ex => ThreadId -> ex -> b
+ throwDynTo, -- :: Typeable ex => ThreadId -> ex -> b
#endif
- catchDyn, -- :: Typeable ex => IO a -> (ex -> IO a) -> IO a
-
- -- * Asynchronous Exceptions
+ catchDyn, -- :: Typeable ex => IO a -> (ex -> IO a) -> IO a
+
+ -- * Asynchronous Exceptions
- -- $async
+ -- $async
- -- ** Asynchronous exception control
+ -- ** Asynchronous exception control
- -- |The following two functions allow a thread to control delivery of
- -- asynchronous exceptions during a critical region.
+ -- |The following two functions allow a thread to control delivery of
+ -- asynchronous exceptions during a critical region.
block, -- :: IO a -> IO a
unblock, -- :: IO a -> IO a
- -- *** Applying @block@ to an exception handler
+ -- *** Applying @block@ to an exception handler
- -- $block_handler
+ -- $block_handler
- -- *** Interruptible operations
+ -- *** Interruptible operations
- -- $interruptible
+ -- $interruptible
- -- * Assertions
+ -- * Assertions
- assert, -- :: Bool -> a -> a
+ assert, -- :: Bool -> a -> a
- -- * Utilities
+ -- * Utilities
- bracket, -- :: IO a -> (a -> IO b) -> (a -> IO c) -> IO ()
- bracket_, -- :: IO a -> IO b -> IO c -> IO ()
- bracketOnError,
+ bracket, -- :: IO a -> (a -> IO b) -> (a -> IO c) -> IO ()
+ bracket_, -- :: IO a -> IO b -> IO c -> IO ()
+ bracketOnError,
- finally, -- :: IO a -> IO b -> IO a
-
+ finally, -- :: IO a -> IO b -> IO a
+
#ifdef __GLASGOW_HASKELL__
- setUncaughtExceptionHandler, -- :: (Exception -> IO ()) -> IO ()
- getUncaughtExceptionHandler -- :: IO (Exception -> IO ())
+ setUncaughtExceptionHandler, -- :: (Exception -> IO ()) -> IO ()
+ getUncaughtExceptionHandler -- :: IO (Exception -> IO ())
#endif
) where
#ifdef __GLASGOW_HASKELL__
-import GHC.Base ( assert )
-import GHC.Exception as ExceptionBase hiding (catch)
-import GHC.Conc ( throwTo, ThreadId )
-import Data.IORef ( IORef, newIORef, readIORef, writeIORef )
+import GHC.Base ( assert )
+import GHC.Exception as ExceptionBase hiding (catch)
+import GHC.Conc ( throwTo, ThreadId )
+import Data.IORef ( IORef, newIORef, readIORef, writeIORef )
import Foreign.C.String ( CString, withCString )
-import System.IO ( stdout, hFlush )
+import System.IO ( stdout, hFlush )
#endif
#ifdef __HUGS__
-import Hugs.Exception as ExceptionBase
+import Hugs.Exception as ExceptionBase
#endif
-import Prelude hiding ( catch )
-import System.IO.Error hiding ( catch, try )
+import Prelude hiding ( catch )
+import System.IO.Error hiding ( catch, try )
import System.IO.Unsafe (unsafePerformIO)
import Data.Dynamic
+#ifdef __NHC__
+import System.IO.Error (catch, ioError)
+import IO (bracket)
+import DIOError -- defn of IOError type
+
+-- minimum needed for nhc98 to pretend it has Exceptions
+type Exception = IOError
+type IOException = IOError
+data ArithException
+data ArrayException
+data AsyncException
+
+throwIO :: Exception -> IO a
+throwIO = ioError
+throw :: Exception -> a
+throw = unsafePerformIO . throwIO
+
+evaluate :: a -> IO a
+evaluate x = x `seq` return x
+
+ioErrors :: Exception -> Maybe IOError
+ioErrors e = Just e
+arithExceptions :: Exception -> Maybe ArithException
+arithExceptions = const Nothing
+errorCalls :: Exception -> Maybe String
+errorCalls = const Nothing
+dynExceptions :: Exception -> Maybe Dynamic
+dynExceptions = const Nothing
+assertions :: Exception -> Maybe String
+assertions = const Nothing
+asyncExceptions :: Exception -> Maybe AsyncException
+asyncExceptions = const Nothing
+userErrors :: Exception -> Maybe String
+userErrors (UserError _ s) = Just s
+userErrors _ = Nothing
+
+block :: IO a -> IO a
+block = id
+unblock :: IO a -> IO a
+unblock = id
+
+assert :: Bool -> a -> a
+assert True x = x
+assert False _ = throw (UserError "" "Assertion failed")
+#endif
+
-----------------------------------------------------------------------------
-- Catching exceptions
--
-- and then using @C.catch@
--
-
-catch :: IO a -- ^ The computation to run
- -> (Exception -> IO a) -- ^ Handler to invoke if an exception is raised
- -> IO a
+#ifndef __NHC__
+catch :: IO a -- ^ The computation to run
+ -> (Exception -> IO a) -- ^ Handler to invoke if an exception is raised
+ -> IO a
catch = ExceptionBase.catchException
-
+#endif
-- | 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. There are
-- are re-raised, and may be caught by an enclosing
-- 'catch' or 'catchJust'.
catchJust
- :: (Exception -> Maybe b) -- ^ Predicate to select exceptions
- -> IO a -- ^ Computation to run
- -> (b -> IO a) -- ^ Handler
- -> IO a
+ :: (Exception -> 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
+ 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 -> IO a) -> IO a -> IO a
+-- > ...
+handle :: (Exception -> IO a) -> IO a -> IO a
handle = flip catch
-- | A version of 'catchJust' with the arguments swapped around (see
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)
+ Right v -> return (Right v)
+ Left e -> case p e of
+ Nothing -> throw e
+ Just b -> return (Left b)
-----------------------------------------------------------------------------
-- Dynamic exceptions
-- | Raise any value as an exception, provided it is in the
-- 'Typeable' class.
throwDyn :: Typeable exception => exception -> b
+#ifdef __NHC__
+throwDyn exception = throw (UserError "" "dynamic exception")
+#else
throwDyn exception = throw (DynException (toDyn exception))
+#endif
#ifdef __GLASGOW_HASKELL__
-- | A variant of 'throwDyn' that throws the dynamic exception to an
-- with dynamic exceptions used in other libraries.
--
catchDyn :: Typeable exception => IO a -> (exception -> IO a) -> IO a
+#ifdef __NHC__
+catchDyn m k = m -- can't catch dyn exceptions in nhc98
+#else
catchDyn m k = catchException m handle
where handle ex = case ex of
- (DynException dyn) ->
- case fromDynamic dyn of
- Just exception -> k exception
- Nothing -> throw ex
- _ -> throw ex
+ (DynException dyn) ->
+ case fromDynamic dyn of
+ Just exception -> k exception
+ Nothing -> throw ex
+ _ -> throw ex
+#endif
-----------------------------------------------------------------------------
-- Exception Predicates
-- These pre-defined predicates may be used as the first argument to
-- 'catchJust', 'tryJust', or 'handleJust' to select certain common
-- classes of exceptions.
-
-ioErrors :: Exception -> Maybe IOError
-arithExceptions :: Exception -> Maybe ArithException
-errorCalls :: Exception -> Maybe String
-assertions :: Exception -> Maybe String
-dynExceptions :: Exception -> Maybe Dynamic
-asyncExceptions :: Exception -> Maybe AsyncException
-userErrors :: Exception -> Maybe String
+#ifndef __NHC__
+ioErrors :: Exception -> Maybe IOError
+arithExceptions :: Exception -> Maybe ArithException
+errorCalls :: Exception -> Maybe String
+assertions :: Exception -> Maybe String
+dynExceptions :: Exception -> Maybe Dynamic
+asyncExceptions :: Exception -> Maybe AsyncException
+userErrors :: Exception -> Maybe String
ioErrors (IOException e) = Just e
ioErrors _ = Nothing
userErrors (IOException e) | isUserError e = Just (ioeGetErrorString e)
userErrors _ = Nothing
-
+#endif
-----------------------------------------------------------------------------
-- Some Useful Functions
-- The arguments to 'bracket' are in this order so that we can partially apply
-- it, e.g.:
--
--- > withFile name = bracket (openFile name) hClose
+-- > 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
+ :: 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 <- catch
- (unblock (thing a))
- (\e -> do { after a; throw e })
+ (unblock (thing a))
+ (\e -> do { after a; throw e })
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
+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 <- catch
- (unblock a)
- (\e -> do { sequel; throw e })
+ (unblock a)
+ (\e -> do { sequel; throw e })
sequel
return r
)
-- | 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
+ :: 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
catch
- (unblock (thing a))
- (\e -> do { after a; throw e })
+ (unblock (thing a))
+ (\e -> do { after a; throw e })
)
-- -----------------------------------------------------------------------------
'System.IO.openFile'.
-}
-#ifndef __GLASGOW_HASKELL__
+#if !(__GLASGOW_HASKELL__ || __NHC__)
assert :: Bool -> a -> a
assert True x = x
assert False _ = throw (AssertionFailed "")
let msg = case ex of
Deadlock -> "no threads to run: infinite loop or deadlock?"
ErrorCall s -> s
- other -> showsPrec 0 other "\n"
+ other -> showsPrec 0 other ""
withCString "%s" $ \cfmt ->
withCString msg $ \cmsg ->
errorBelch cfmt cmsg