-- Stability : experimental
-- Portability : non-portable
--
--- The External API for exceptions. The functions provided in this
--- module allow catching of exceptions in the IO monad.
+-- This module provides support for raising and catching both built-in
+-- and user-defined exceptions.
--
-----------------------------------------------------------------------------
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
- try, -- :: IO a -> IO (Either Exception a)
- tryJust, -- :: (Exception -> Maybe b) -> a -> IO (Either b a)
+ -- * Throwing exceptions
+ throw, -- :: Exception -> a
+ ioError, -- :: Exception -> IO a
+ throwTo, -- :: ThreadId -> Exception -> a
+ -- * Catching Exceptions
+
+ -- |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 @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 @evaluate@ function
evaluate, -- :: a -> IO a
- -- Exception predicates (for tryJust, catchJust, handleJust)
+ -- ** Exception predicates
+
+ -- $preds
ioErrors, -- :: Exception -> Maybe IOError
arithExceptions, -- :: Exception -> Maybe ArithException
asyncExceptions, -- :: Exception -> Maybe AsyncException
userErrors, -- :: Exception -> Maybe String
- -- Throwing exceptions
-
- throw, -- :: Exception -> a
- throwTo, -- :: ThreadId -> Exception -> a
-
- -- Dynamic exceptions
+ -- * Dynamic exceptions
+ -- $dynamic
throwDyn, -- :: Typeable ex => ex -> b
throwDynTo, -- :: Typeable ex => ThreadId -> ex -> b
catchDyn, -- :: Typeable ex => IO a -> (ex -> IO a) -> IO a
- -- Async exception control
+ -- * Asynchronous Exceptions
+
+ -- $async
+
+ -- ** Asynchronous exception control
+
+ -- |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
- -- Assertions
+ -- *** Applying @block@ to an exception handler
- -- for now
- assert, -- :: Bool -> a -> a
+ -- $block_handler
- -- Utilities
+ -- *** Interruptible operations
- finally, -- :: IO a -> IO b -> IO b
+ -- $interruptible
+
+ -- * Assertions
+
+ assert, -- :: Bool -> a -> a
+
+ -- * Utilities
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
+
) where
#ifdef __GLASGOW_HASKELL__
-----------------------------------------------------------------------------
-- Catching exceptions
--- GHC.Exception defines 'catchException' for us.
-
-catch :: IO a -> (Exception -> IO a) -> IO a
-catch = catchException
-
-catchJust :: (Exception -> Maybe b) -> IO a -> (b -> IO a) -> IO a
+-- |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
+-- 'ioError'. 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
+-- "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' when importing
+-- "Control.Exception", or importing
+-- "Control.Exception" qualified, to avoid name-clashes.
+
+catch :: IO a -- ^ The computation to run
+ -> (Exception -> IO a) -- ^ Handler to invoke if an exception is raised
+ -> IO a
+catch = GHC.Exception.catchException
+
+-- | 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
+-- some predefined exception predicates for useful subsets of
+-- exceptions: 'ioErrors', 'arithExceptions', and so on. For example,
+-- to catch just calls to the 'error' function, we could use
+--
+-- > 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 -> 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 -> IO a) -> IO a -> IO a
handle = flip catch
+-- | A version of 'catchJust' with the arguments swapped around (see
+-- 'handle').
handleJust :: (Exception -> Maybe b) -> (b -> IO a) -> IO a -> IO a
handleJust p = flip (catchJust p)
-----------------------------------------------------------------------------
-- evaluate
+-- | Forces its argument to be evaluated, and returns the result in
+-- the 'IO' monad. It can be used to order evaluation with respect to
+-- other 'IO' operations; its semantics are given by
+--
+-- > evaluate undefined `seq` return () ==> return ()
+-- > catch (evaluate undefined) (\e -> return ()) ==> return ()
+--
+-- NOTE: @(evaluate a)@ is /not/ the same as @(a \`seq\` return a)@.
evaluate :: a -> IO a
-evaluate a = a `seq` return a
+evaluate a = IO $ \s -> a `seq` (# s, a #)
-----------------------------------------------------------------------------
-- '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.
+--
try :: IO a -> IO (Either Exception 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 -> Maybe b) -> IO a -> IO (Either b a)
tryJust p a = do
r <- try a
Just b -> return (Left b)
-----------------------------------------------------------------------------
--- Dynamic exception types. Since one of the possible kinds of exception
--- is a dynamically typed value, we can effectively have polymorphic
--- exceptions.
-
--- throwDyn will raise any value as an exception, provided it is in the
--- Typeable class (see Dynamic.lhs).
+-- Dynamic exceptions
--- catchDyn will catch any exception of a given type (determined by the
--- handler function). Any raised exceptions that don't match are
--- re-raised.
+-- $dynamic
+-- 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.
+-- | Raise any value as an exception, provided it is in the
+-- 'Typeable' class.
throwDyn :: Typeable exception => exception -> b
throwDyn exception = throw (DynException (toDyn exception))
+-- | A variant of 'throwDyn' that throws the dynamic exception to an
+-- arbitrary thread (c.f. 'throwTo').
throwDynTo :: Typeable exception => ThreadId -> exception -> IO ()
throwDynTo t exception = throwTo t (DynException (toDyn exception))
+-- | Catch dynamic exceptions of the required type. All other
+-- exceptions are re-thrown, including dynamic exceptions of the wrong
+-- type.
+--
+-- When using dynamic exceptions it is advisable to define a new
+-- datatype to use for your exception type, to avoid possible clashes
+-- with dynamic exceptions used in other libraries.
+--
catchDyn :: Typeable exception => IO a -> (exception -> IO a) -> IO a
catchDyn m k = catchException m handle
where handle ex = case ex of
-----------------------------------------------------------------------------
-- Exception Predicates
+-- $preds
+-- 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
-----------------------------------------------------------------------------
-- Some Useful Functions
-bracket :: IO a -> (a -> IO b) -> (a -> IO c) -> IO c
+-- | 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 = bracket (openFile name) hClose
+--
+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
return r
)
--- finally is an instance of bracket, but it's quite common
--- so we give the specialised version for efficiency.
-finally :: IO a -> IO b -> IO a
+
+-- | 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 <- catch
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)
+
+-- -----------------------------------------------------------------------------
+-- Asynchronous exceptions
+
+{- $async
+
+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.
+
+The primary source of asynchronous exceptions, however, is
+'throwTo':
+
+> throwTo :: ThreadId -> Exception -> IO ()
+
+'throwTo' (also 'throwDynTo' and '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.
+Great care should be taken with asynchronous exceptions; it is all too
+easy to introduce race conditions by the over zealous use of
+'throwTo'.
+-}
+
+{- $block_handler
+There\'s an implied 'block' around every exception handler in a call
+to one of the 'catch' family of functions. This is because that is
+what you want most of the time - it eliminates a common race condition
+in starting an exception handler, because there may be no exception
+handler on the stack to handle another exception if one arrives
+immediately. If asynchronous exceptions are blocked on entering the
+handler, though, we have time to install a new exception handler
+before being interrupted. If this weren\'t the default, one would have
+to write something like
+
+> block (
+> catch (unblock (...))
+> (\e -> handler)
+> )
+
+If you need to unblock asynchronous exceptions again in the exception
+handler, just use 'unblock' as normal.
+
+Note that 'try' and friends /do not/ have a similar default, because
+there is no exception handler in this case. If you want to use 'try'
+in an asynchronous-exception-safe way, you will need to use
+'block'.
+-}
+
+{- $interruptible
+
+Some operations are /interruptible/, which means that they can receive
+asynchronous exceptions even in the scope of a 'block'. Any function
+which may itself block is defined as interruptible; this includes
+'takeMVar' (but not 'tryTakeMVar'), and most operations which perform
+some I\/O with the outside world.. The reason for having
+interruptible operations is so that we can write things like
+
+> block (
+> a <- takeMVar m
+> catch (unblock (...))
+> (\e -> ...)
+> )
+
+if the 'takeMVar' was not interruptible, then this particular
+combination could lead to deadlock, because the thread itself would be
+blocked in a state where it can\'t receive any asynchronous exceptions.
+With 'takeMVar' interruptible, however, we can be
+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'.
+-}
+
+-- -----------------------------------------------------------------------------
+-- Assert
+
+#ifdef __HADDOCK__
+-- | If the first argument evaluates to 'True', then the result is the
+-- second argument. Otherwise an 'Assertion' exception is raised,
+-- containing a 'String' with the source file and line number of the
+-- call to assert.
+--
+-- Assertions can normally be turned on or off with a compiler flag
+-- (for GHC, assertions are normally on unless the @-fignore-asserts@
+-- option is give). When assertions are turned off, the first
+-- argument to 'assert' is ignored, and the second argument is
+-- returned as the result.
+assert :: Bool -> a -> a
+#endif
-- with operations for converting dynamic values into a concrete
-- (monomorphic) type.
--
--- The Dynamic implementation provided is closely based on code
--- contained in Hugs library of the same name.
---
-----------------------------------------------------------------------------
module Data.Dynamic
- (
- -- dynamic type
- Dynamic -- abstract, instance of: Show, Typeable
- , toDyn -- :: Typeable a => a -> Dynamic
- , fromDyn -- :: Typeable a => Dynamic -> a -> a
- , fromDynamic -- :: Typeable a => Dynamic -> Maybe a
+ (
+ -- * The @Dynamic@ type
+ Dynamic, -- abstract, instance of: Show, Typeable
+
+ -- * Converting to and from @Dynamic@
+ toDyn, -- :: Typeable a => a -> Dynamic
+ fromDyn, -- :: Typeable a => Dynamic -> a -> a
+ fromDynamic, -- :: Typeable a => Dynamic -> Maybe a
- -- type representation
-
- , Typeable(
- typeOf) -- :: a -> TypeRep
+ -- * Concrete Type Representations
+
+ -- | This section is useful if you need to define your own
+ -- instances of 'Typeable'.
- -- Dynamic defines Typeable instances for the following
- -- Prelude types: [a], (), (a,b), (a,b,c), (a,b,c,d),
- -- (a,b,c,d,e), (a->b), (Array a b), Bool, Char,
- -- (Complex a), Double, (Either a b), Float, Handle,
- -- Int, Integer, (IO a), (Maybe a), Ordering
+ Typeable(
+ typeOf), -- :: a -> TypeRep
- , TypeRep -- abstract, instance of: Eq, Show, Typeable
- , TyCon -- abstract, instance of: Eq, Show, Typeable
+ -- ** Building concrete type representations
+ TypeRep, -- abstract, instance of: Eq, Show, Typeable
+ TyCon, -- abstract, instance of: Eq, Show, Typeable
- -- type representation constructors/operators:
- , mkTyCon -- :: String -> TyCon
- , mkAppTy -- :: TyCon -> [TypeRep] -> TypeRep
- , mkFunTy -- :: TypeRep -> TypeRep -> TypeRep
- , applyTy -- :: TypeRep -> TypeRep -> Maybe TypeRep
+ mkTyCon, -- :: String -> TyCon
+ mkAppTy, -- :: TyCon -> [TypeRep] -> TypeRep
+ mkFunTy, -- :: TypeRep -> TypeRep -> TypeRep
+ applyTy, -- :: TypeRep -> TypeRep -> Maybe TypeRep
--
-- let fTy = mkTyCon "Foo" in show (mkAppTy (mkTyCon ",,")
#include "Dynamic.h"
--- The dynamic type is represented by Dynamic, carrying
--- the dynamic value along with its type representation:
+{-|
+ A value of type 'Dynamic' is an object encapsulated together with its type.
+ A 'Dynamic' may only represent a monomorphic value; an attempt to
+ create a value of type 'Dynamic' from a polymorphically-typed
+ expression will result in an ambiguity error (see 'toDyn').
+
+ 'Show'ing a value of type 'Dynamic' returns a pretty-printed representation
+ of the object\'s type; useful for debugging.
+-}
data Dynamic = Dynamic TypeRep Obj
instance Show Dynamic where
data Obj = Obj
-- dummy type to hold the dynamically typed value.
+-- | A concrete representation of a (monomorphic) type. 'TypeRep'
+-- supports reasonably efficient equality.
data TypeRep
- = App TyCon [TypeRep]
+ = App TyCon [TypeRep]
| Fun TypeRep TypeRep
deriving ( Eq )
showParen (p > 8) $
showsPrec 9 f . showString " -> " . showsPrec 8 a
--- type constructors are
+-- | An abstract representation of a type constructor. 'TyCon' objects can
+-- be built using 'mkTyCon'.
data TyCon = TyCon Int String
instance Eq TyCon where
instance Show TyCon where
showsPrec _ (TyCon _ s) = showString s
--- Operations for going to and from Dynamic:
+-- | Converts an arbitrary value into an object of type 'Dynamic'.
+--
+-- The type of the object must be an instance of 'Typeable', which
+-- ensures that only monomorphically-typed objects may be converted to
+-- 'Dynamic'. To convert a polymorphic object into 'Dynamic', give it
+-- a monomorphic type signature. For example:
+--
+-- > toDyn (id :: Int -> Int)
+--
toDyn :: Typeable a => a -> Dynamic
toDyn v = Dynamic (typeOf v) (unsafeCoerce v)
-fromDyn :: Typeable a => Dynamic -> a -> a
+-- | Converts a 'Dynamic' object back into an ordinary Haskell value of
+-- the correct type. See also 'fromDynamic'.
+fromDyn :: Typeable a
+ => Dynamic -- ^ the dynamically-typed object
+ -> a -- ^ a default value
+ -> a -- ^ returns: the value of the first argument, if
+ -- it has the correct type, otherwise the value of
+ -- the second argument.
fromDyn (Dynamic t v) def
| typeOf def == t = unsafeCoerce v
| otherwise = def
-fromDynamic :: Typeable a => Dynamic -> Maybe a
+-- | Converts a 'Dynamic' object back into an ordinary Haskell value of
+-- the correct type. See also 'fromDyn'.
+fromDynamic
+ :: Typeable a
+ => Dynamic -- ^ the dynamically-typed object
+ -> Maybe a -- ^ returns: @'Just' a@, if the dyanmically-typed
+ -- object has the correct type (and @a@ is its value),
+ -- or 'Nothing' otherwise.
fromDynamic (Dynamic t v) =
case unsafeCoerce v of
r | t == typeOf r -> Just r
| otherwise -> Nothing
--- To make it possible to convert values with user-defined types
--- into type Dynamic, we need a systematic way of getting
--- the type representation of an arbitrary type. A type
--- class provides just the ticket,
-
+-- | The class 'Typeable' allows a concrete representation of a type to
+-- be calculated.
class Typeable a where
typeOf :: a -> TypeRep
-
--- NOTE: The argument to the overloaded `typeOf' is only
--- used to carry type information, and Typeable instances
--- should *never* *ever* look at its value.
+ -- ^ Takes a value of type @a@ and returns a concrete representation
+ -- of that type. The /value/ of the argument should be ignored by
+ -- any instance of 'Typeable', so that it is safe to pass 'undefined' as
+ -- the argument.
isTupleTyCon :: TyCon -> Bool
isTupleTyCon (TyCon _ (',':_)) = True
-- If this constraint does turn out to be a sore thumb, changing
-- the Eq instance for TyCons is trivial.
-mkTyCon :: String -> TyCon
+-- | Builds a 'TyCon' object representing a type constructor. An
+-- implementation of "Data.Dynamic" should ensure that the following holds:
+--
+-- > mkTyCon "a" == mkTyCon "a"
+--
+-- NOTE: GHC\'s implementation is quite hacky, and the above equation
+-- does not necessarily hold. For defining your own instances of
+-- 'Typeable', try to ensure that only one call to 'mkTyCon' exists
+-- for each type constructor (put it at the top level, and annotate the
+-- corresponding definition with a @NOINLINE@ pragma).
+mkTyCon
+ :: String -- ^ the name of the type constructor (should be unique
+ -- in the program, so it might be wise to use the
+ -- fully qualified name).
+ -> TyCon -- ^ A unique 'TyCon' object
mkTyCon str = unsafePerformIO $ do
v <- readIORef uni
writeIORef uni (v+1)
go _ _ = showChar ')'
+-- | Applies a type constructor to a sequence of types
mkAppTy :: TyCon -> [TypeRep] -> TypeRep
mkAppTy tyc args = App tyc args
+-- | A special case of 'mkAppTy', which applies the function type constructor to
+-- a pair of types.
mkFunTy :: TypeRep -> TypeRep -> TypeRep
mkFunTy f a = Fun f a
"Can't apply function " ++ show f ++
" to argument " ++ show x)
+-- | Applies a type to a function type. Returns: @'Just' u@ if the
+-- first argument represents a function of type @t -> u@ and the
+-- second argument represents a function of type @t@. Otherwise,
+-- returns 'Nothing'.
applyTy :: TypeRep -> TypeRep -> Maybe TypeRep
applyTy (Fun t1 t2) t3
| t1 == t3 = Just t2
%*********************************************************
\begin{code}
-#ifndef __HUGS__
+-- | Applying 'block' to a computation will
+-- execute that computation with asynchronous exceptions
+-- /blocked/. That is, any thread which
+-- attempts to raise an exception in the current thread will be
+-- blocked until asynchronous exceptions are enabled again. There\'s
+-- no need to worry about re-enabling asynchronous exceptions; that is
+-- done automatically on exiting the scope of
+-- 'block'.
block :: IO a -> IO a
-block (IO io) = IO $ blockAsyncExceptions# io
+-- | To re-enable asynchronous exceptions inside the scope of
+-- 'block', 'unblock' can be
+-- used. It scopes in exactly the same way, so on exit from
+-- 'unblock' asynchronous exception delivery will
+-- be disabled again.
unblock :: IO a -> IO a
+
+#ifndef __HUGS__
+block (IO io) = IO $ blockAsyncExceptions# io
unblock (IO io) = IO $ unblockAsyncExceptions# io
#else
--- Not implemented yet in Hugs.
-block :: IO a -> IO a
-block (IO io) = IO io
-
unblock :: IO a -> IO a
unblock (IO io) = IO io
#endif
-- ------------------------------------------------------------------------
-- Exception datatype and operations
+-- |The type of exceptions. Every kind of system-generated exception
+-- has a constructor in the 'Exception' type, and values of other
+-- types may be injected into 'Exception' by coercing them to
+-- 'Dynamic' (see the section on Dynamic Exceptions).
+--
+-- For backwards compatibility with Haskell 98, 'IOError' is a type synonym
+-- for 'Exception'.
data Exception
- = IOException IOException -- IO exceptions
- | ArithException ArithException -- Arithmetic exceptions
- | ArrayException ArrayException -- Array-related exceptions
- | ErrorCall String -- Calls to 'error'
- | ExitException ExitCode -- Call to System.exitWith
- | NoMethodError String -- A non-existent method was invoked
- | PatternMatchFail String -- A pattern match / guard failure
- | RecSelError String -- Selecting a non-existent field
- | RecConError String -- Field missing in record construction
- | RecUpdError String -- Record doesn't contain updated field
- | AssertionFailed String -- Assertions
- | DynException Dynamic -- Dynamic exceptions
- | AsyncException AsyncException -- Externally generated errors
- | BlockedOnDeadMVar -- Blocking on a dead MVar
- | Deadlock -- no threads can run (raised in main thread)
+ = ArithException ArithException
+ -- ^Exceptions raised by arithmetic
+ -- operations. (NOTE: GHC currently does not throw
+ -- 'ArithException's).
+ | ArrayException ArrayException
+ -- ^Exceptions raised by array-related
+ -- operations. (NOTE: GHC currently does not throw
+ -- 'ArrayException's).
+ | AssertionFailed String
+ -- ^This exception is thrown by the
+ -- 'assert' operation when the condition
+ -- fails. The 'String' argument contains the
+ -- location of the assertion in the source program.
+ | AsyncException AsyncException
+ -- ^Asynchronous exceptions (see section on Asynchronous Exceptions).
+ | BlockedOnDeadMVar
+ -- ^The current thread was executing a call to
+ -- 'takeMVar' that could never return, because there are no other
+ -- references to this 'MVar'.
+ | Deadlock
+ -- ^There are no runnable threads, so the program is
+ -- deadlocked. The 'Deadlock' exception is
+ -- raised in the main thread only (see also: "Control.Concurrent").
+ | DynException Dynamic
+ -- ^Dynamically typed exceptions (see section on Dynamic Exceptions).
+ | ErrorCall String
+ -- ^The 'ErrorCall' exception is thrown by 'error'. The 'String'
+ -- argument of 'ErrorCall' is the string passed to 'error' when it was
+ -- called.
+ | ExitException ExitCode
+ -- ^The 'ExitException' exception is thrown by 'System.exitWith' (and
+ -- 'System.exitFailure'). The 'ExitCode' argument is the value passed
+ -- to 'System.exitWith'. An unhandled 'ExitException' exception in the
+ -- main thread will cause the program to be terminated with the given
+ -- exit code.
+ | IOException IOException
+ -- ^These are the standard IO exceptions generated by
+ -- Haskell\'s @IO@ operations. See also "System.IO.Error".
+ | NoMethodError String
+ -- ^An attempt was made to invoke a class method which has
+ -- no definition in this instance, and there was no default
+ -- definition given in the class declaration. GHC issues a
+ -- warning when you compile an instance which has missing
+ -- methods.
| NonTermination
-
+ -- ^The current thread is stuck in an infinite loop. This
+ -- exception may or may not be thrown when the program is
+ -- non-terminating.
+ | PatternMatchFail String
+ -- ^A pattern matching failure. The 'String' argument should contain a
+ -- descriptive message including the function name, source file
+ -- and line number.
+ | RecConError String
+ -- ^An attempt was made to evaluate a field of a record
+ -- for which no value was given at construction time. The
+ -- 'String' argument gives the location of the
+ -- record construction in the source program.
+ | RecSelError String
+ -- ^A field selection was attempted on a constructor that
+ -- doesn\'t have the requested field. This can happen with
+ -- multi-constructor records when one or more fields are
+ -- missing from some of the constructors. The
+ -- 'String' argument gives the location of the
+ -- record selection in the source program.
+ | RecUpdError String
+ -- ^An attempt was made to update a field in a record,
+ -- where the record doesn\'t have the requested field. This can
+ -- only occur with multi-constructor records, when one or more
+ -- fields are missing from some of the constructors. The
+ -- 'String' argument gives the location of the
+ -- record update in the source program.
+
+-- |The type of arithmetic exceptions
data ArithException
= Overflow
| Underflow
| Denormal
deriving (Eq, Ord)
+
+-- |Asynchronous exceptions
data AsyncException
= StackOverflow
+ -- ^The current thread\'s stack exceeded its limit.
+ -- Since an exception has been raised, the thread\'s stack
+ -- will certainly be below its limit again, but the
+ -- programmer should take remedial action
+ -- immediately.
| HeapOverflow
+ -- ^The program\'s heap is reaching its limit, and
+ -- the program should take action to reduce the amount of
+ -- live data it has. Notes:
+ --
+ -- * It is undefined which thread receives this exception.
+ --
+ -- * GHC currently does not throw 'HeapOverflow' exceptions.
| ThreadKilled
+ -- ^This exception is raised by another thread
+ -- calling 'killThread', or by the system
+ -- if it needs to terminate the thread for some
+ -- reason.
deriving (Eq, Ord)
+-- | Exceptions generated by array operations
data ArrayException
- = IndexOutOfBounds String -- out-of-range array access
- | UndefinedElement String -- evaluating an undefined element
+ = IndexOutOfBounds String
+ -- ^An attempt was made to index an array outside
+ -- its declared bounds.
+ | UndefinedElement String
+ -- ^An attempt was made to evaluate an element of an
+ -- array that had not been initialized.
deriving (Eq, Ord)
stackOverflow, heapOverflow :: Exception -- for the RTS
-- --------------------------------------------------------------------------
-- Primitive throw
+-- | Throw an exception. Exceptions may be thrown from purely
+-- functional code, but may only be caught within the 'IO' monad.
throw :: Exception -> a
throw exception = raise# exception
+-- | A variant of 'throw' that can be used within the 'IO' monad.
+--
+-- Although 'ioError' has a type that is an instance of the type of 'throw', the
+-- two functions are subtly different:
+--
+-- > throw e `seq` return () ===> throw e
+-- > ioError e `seq` return () ===> return ()
+--
+-- The first example will cause the exception @e@ to be raised,
+-- whereas the second one won\'t. In fact, 'ioError' will only cause
+-- an exception to be raised when it is used within the 'IO' monad.
+-- The 'ioError' variant should be used in preference to 'throw' to
+-- raise an exception within the 'IO' monad because it guarantees
+-- ordering with respect to other 'IO' operations, whereas 'throw'
+-- does not.
ioError :: Exception -> IO a
ioError err = IO $ \s -> throw err s
------------------------------------------------------------------------
-- ReadS
+-- | A parser for a type @a@, represented as a function that takes a
+-- 'String' and returns a list of possible parses @(a,'String')@ pairs.
type ReadS a = String -> [(a,String)]
------------------------------------------------------------------------