    \begin{code}
    {-# OPTIONS_GHC -XNoImplicitPrelude #-}
    {-# OPTIONS_HADDOCK hide #-}
    -----------------------------------------------------------------------------
    -- |
    -- Module      :  GHC.Exception
    -- Copyright   :  (c) The University of Glasgow, 1998-2002
    -- License     :  see libraries/base/LICENSE
    --
    -- Maintainer  :  cvs-ghc@haskell.org
    -- Stability   :  internal
    -- Portability :  non-portable (GHC extensions)
    --
    -- Exceptions and exception-handling functions.
    --
    -----------------------------------------------------------------------------

    -- #hide
    module GHC.Exception where

    import Data.Maybe
    import {-# SOURCE #-} Data.Typeable
    import GHC.Base
    import GHC.Show
    \end{code}

    %*********************************************************
    %*                                                      *
    \subsection{Exceptions}
    %*                                                      *
    %*********************************************************

    \begin{code}
    {- |
    The @SomeException@ type is the root of the exception type hierarchy.
    When an exception of type @e@ is thrown, behind the scenes it is
    encapsulated in a @SomeException@.
    -}
    data SomeException = forall e . Exception e => SomeException e
        deriving Typeable

    instance Show SomeException where
        showsPrec p (SomeException e) = showsPrec p e

    {- |
    Any type that you wish to throw or catch as an exception must be an
    instance of the @Exception@ class. The simplest case is a new exception
    type directly below the root:

    > data MyException = ThisException | ThatException
    >     deriving (Show, Typeable)
    >
    > instance Exception MyException

    The default method definitions in the @Exception@ class do what we need
    in this case. You can now throw and catch @ThisException@ and
    @ThatException@ as exceptions:

    @
    *Main> throw ThisException `catch` \e -> putStrLn (\"Caught \" ++ show (e :: MyException))
    Caught ThisException
    @

    In more complicated examples, you may wish to define a whole hierarchy
    of exceptions:

    > ---------------------------------------------------------------------
    > -- Make the root exception type for all the exceptions in a compiler
    >
    > data SomeCompilerException = forall e . Exception e => SomeCompilerException e
    >     deriving Typeable
    >
    > instance Show SomeCompilerException where
    >     show (SomeCompilerException e) = show e
    >
    > instance Exception SomeCompilerException
    >
    > compilerExceptionToException :: Exception e => e -> SomeException
    > compilerExceptionToException = toException . SomeCompilerException
    >
    > compilerExceptionFromException :: Exception e => SomeException -> Maybe e
    > compilerExceptionFromException x = do
    >     SomeCompilerException a <- fromException x
    >     cast a
    >
    > ---------------------------------------------------------------------
    > -- Make a subhierarchy for exceptions in the frontend of the compiler
    >
    > data SomeFrontendException = forall e . Exception e => SomeFrontendException e
    >     deriving Typeable
    >
    > instance Show SomeFrontendException where
    >     show (SomeFrontendException e) = show e
    >
    > instance Exception SomeFrontendException where
    >     toException = compilerExceptionToException
    >     fromException = compilerExceptionFromException
    >
    > frontendExceptionToException :: Exception e => e -> SomeException
    > frontendExceptionToException = toException . SomeFrontendException
    >
    > frontendExceptionFromException :: Exception e => SomeException -> Maybe e
    > frontendExceptionFromException x = do
    >     SomeFrontendException a <- fromException x
    >     cast a
    >
    > ---------------------------------------------------------------------
    > -- Make an exception type for a particular frontend compiler exception
    >
    > data MismatchedParentheses = MismatchedParentheses
    >     deriving (Typeable, Show)
    >
    > instance Exception MismatchedParentheses where
    >     toException   = frontendExceptionToException
    >     fromException = frontendExceptionFromException

    We can now catch a @MismatchedParentheses@ exception as
    @MismatchedParentheses@, @SomeFrontendException@ or
    @SomeCompilerException@, but not other types, e.g. @IOException@:

    @
    *Main> throw MismatchedParentheses `catch` \e -> putStrLn (\"Caught \" ++ show (e :: MismatchedParentheses))
    Caught MismatchedParentheses
    *Main> throw MismatchedParentheses `catch` \e -> putStrLn (\"Caught \" ++ show (e :: SomeFrontendException))
    Caught MismatchedParentheses
    *Main> throw MismatchedParentheses `catch` \e -> putStrLn (\"Caught \" ++ show (e :: SomeCompilerException))
    Caught MismatchedParentheses
    *Main> throw MismatchedParentheses `catch` \e -> putStrLn (\"Caught \" ++ show (e :: IOException))
    *** Exception: MismatchedParentheses
    @

    -}
    class (Typeable e, Show e) => Exception e where
        toException   :: e -> SomeException
        fromException :: SomeException -> Maybe e

        toException = SomeException
        fromException (SomeException e) = cast e

    instance Exception SomeException where
        toException se = se
        fromException = Just
    \end{code}

    %*********************************************************
    %*                                                      *
    \subsection{Primitive throw}
    %*                                                      *
    %*********************************************************

    \begin{code}
    -- | Throw an exception.  Exceptions may be thrown from purely
    -- functional code, but may only be caught within the 'IO' monad.
    throw :: Exception e => e -> a
    throw e = raise# (toException e)
    \end{code}

    \begin{code}
    -- |This is thrown when the user calls 'error'. The @String@ is the
    -- argument given to 'error'.
    data ErrorCall = ErrorCall String
        deriving Typeable

    instance Exception ErrorCall

    instance Show ErrorCall where
        showsPrec _ (ErrorCall err) = showString err

    -----

    -- |Arithmetic exceptions.
    data ArithException
      = Overflow
      | Underflow
      | LossOfPrecision
      | DivideByZero
      | Denormal
      deriving (Eq, Ord, Typeable)

    instance Exception ArithException

    instance Show ArithException where
      showsPrec _ Overflow        = showString "arithmetic overflow"
      showsPrec _ Underflow       = showString "arithmetic underflow"
      showsPrec _ LossOfPrecision = showString "loss of precision"
      showsPrec _ DivideByZero    = showString "divide by zero"
      showsPrec _ Denormal        = showString "denormal"

    \end{code}