Next Previous Contents

6. Exception

The Exception library provides an interface for raising and catching both built-in and user defined exceptions.

Exceptions are defined by the following (non-abstract) datatype:

data Exception
  = IOException         IOError    -- IO exceptions (from 'fail')
  | ArithException      ArithError -- Arithmetic exceptions
  | ErrorCall           String     -- Calls to 'error'
  | NoMethodError       String     -- A non-existent method was invoked
  | PatternMatchFail    String     -- A pattern match failed
  | NonExhaustiveGuards String     -- A guard match failed
  | 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
  | ExternalException   ExtError   -- External exceptions

instance Eq   Exception
instance Ord  Exception
instance Show Exception

data ArithError
  = Overflow
  | Underflow
  | LossOfPrecision
  | DivideByZero
  | Denormal

instance Eq   ArithError
instance Ord  ArithError
instance Show ArithError

data ExtError
  = StackOverflow
  | HeapOverflow
  | ThreadKilled

instance Eq   ExtError
instance Ord  ExtError
instance Show ExtError

An implementation should raise the appropriate exception when one of the above conditions arises. Note: GHC currently doesn't generate the arithmetic or the external exceptions.

Exceptions may be thrown explicitly from anywhere:

throw :: Exception -> a

Exceptions may be caught and examined in the IO monad:

catch       :: IO a -> (Exception  -> IO a) -> IO a
catchIO     :: IO a -> (IOError    -> IO a) -> IO a
catchArith  :: IO a -> (ArithError -> IO a) -> IO a
catchError  :: IO a -> (String     -> IO a) -> IO a

getException   :: a -> IO (Maybe Exception)
getExceptionIO :: IO a -> IO (Either Exception a)

Each of the functions catchIO, catchArith, and catchError only catch a specific type of exception. All other exceptions are effectively re-thrown. An uncaught exception will normally cause the program to terminate, with the offending exception displayed.

Note that catchIO is identical to IO.catch. The implementation of IO errors in GHC and Hugs uses exceptions for speed.

Also, don't forget to import Prelude hidiing (catch) when using this library, to avoid the name clash between Exception.catch and IO.catch.

The getException function is useful for evaluating a non-IO typed value and testing for exceptions. getException evaluates its first argument (as if you'd applied seq to it), returning Just <exception> if an exception was raised, or Nothing otherwise. Note that due to Haskell's unspecified evaluation order, an expression may return one of several possible exceptions: consider the expression error "urk" + 10/. Does getException return Just (ErrorCall "urk") or Just (ArithError DivideByZero)? The answer is "either": getException makes a non-deterministic choice about which exception to return. If you call it again, you might get a different exception back. This is ok, because getException is an IO computation.

getExceptionIO is the equivalent function for IO computations --- it runs its first argument, and returns either the return value or the exception if one was raised. Passing a value of type IO a to getException won't work, because the IO type is represented by a function, and getException will only evaluate its argument to head normal form, hence the IO computation won't be performed. Use getExceptionIO instead.

6.1 Dynamic Exceptions

Because the Exception datatype isn't extendible, we added an interface for throwing and catching exceptions of type Dynamic (see Section Dynamic), which allows exception values of any type in the Typeable class to be thrown and caught.

throwDyn :: Typeable exception => exception -> b
catchDyn :: Typeable exception => IO a -> (exception -> IO a) -> IO a

The catchDyn function only catches exceptions of the required type; all other exceptions are re-thrown as with catchIO and friends above.


Next Previous Contents