Remove Control.Parallel*, now in package parallel
[haskell-directory.git] / GHC / IOBase.lhs
index 6ef6b06..896806a 100644 (file)
@@ -1,26 +1,66 @@
-% ------------------------------------------------------------------------------
-% $Id: IOBase.lhs,v 1.7 2002/03/14 12:09:50 simonmar Exp $
-% 
-% (c) The University of Glasgow, 1994-2001
-%
-
-% Definitions for the @IO@ monad and its friends.  Everything is exported
-% concretely; the @IO@ module itself exports abstractly.
-
 \begin{code}
-{-# OPTIONS -fno-implicit-prelude #-}
-
-module GHC.IOBase where
-
+{-# OPTIONS_GHC -fno-implicit-prelude #-}
+-----------------------------------------------------------------------------
+-- |
+-- Module      :  GHC.IOBase
+-- Copyright   :  (c) The University of Glasgow 1994-2002
+-- License     :  see libraries/base/LICENSE
+-- 
+-- Maintainer  :  cvs-ghc@haskell.org
+-- Stability   :  internal
+-- Portability :  non-portable (GHC Extensions)
+--
+-- Definitions for the 'IO' monad and its friends.
+--
+-----------------------------------------------------------------------------
+
+-- #hide
+module GHC.IOBase(
+    IO(..), unIO, failIO, liftIO, bindIO, thenIO, returnIO, 
+    unsafePerformIO, unsafeInterleaveIO,
+    unsafeDupablePerformIO, unsafeDupableInterleaveIO,
+    noDuplicate,
+  
+       -- To and from from ST
+    stToIO, ioToST, unsafeIOToST, unsafeSTToIO,
+
+       -- References
+    IORef(..), newIORef, readIORef, writeIORef, 
+    IOArray(..), newIOArray, readIOArray, writeIOArray, unsafeReadIOArray, unsafeWriteIOArray,
+    MVar(..),
+
+       -- Handles, file descriptors,
+    FilePath,  
+    Handle(..), Handle__(..), HandleType(..), IOMode(..), FD, 
+    isReadableHandleType, isWritableHandleType, isReadWriteHandleType, showHandle,
+  
+       -- Buffers
+    Buffer(..), RawBuffer, BufferState(..), BufferList(..), BufferMode(..),
+    bufferIsWritable, bufferEmpty, bufferFull, 
+
+       -- Exceptions
+    Exception(..), ArithException(..), AsyncException(..), ArrayException(..),
+    stackOverflow, heapOverflow, throw, throwIO, ioException, 
+    IOError, IOException(..), IOErrorType(..), ioError, userError,
+    ExitCode(..) 
+  ) where
+       
 import GHC.ST
+import GHC.Arr -- to derive Ix class
+import GHC.Enum -- to derive Enum class
 import GHC.STRef
 import GHC.Base
-import GHC.Num -- To get fromInteger etc, needed because of -fno-implicit-prelude
+--  import GHC.Num     -- To get fromInteger etc, needed because of -fno-implicit-prelude
 import Data.Maybe  ( Maybe(..) )
 import GHC.Show
 import GHC.List
 import GHC.Read
-import {-# SOURCE #-} Data.Dynamic
+import Foreign.C.Types (CInt)
+
+#ifndef __HADDOCK__
+import {-# SOURCE #-} Data.Typeable    ( showsTypeRep )
+import {-# SOURCE #-} Data.Dynamic     ( Dynamic, dynTypeRep )
+#endif
 
 -- ---------------------------------------------------------------------------
 -- The IO Monad
@@ -48,6 +88,19 @@ Libraries - parts of hslibs/lang.
 --SDM
 -}
 
+{-|
+A value of type @'IO' a@ is a computation which, when performed,
+does some I\/O before returning a value of type @a@.  
+
+There is really only one way to \"perform\" an I\/O action: bind it to
+@Main.main@ in your program.  When your program is run, the I\/O will
+be performed.  It isn't possible to perform I\/O from an arbitrary
+function, unless that function is itself in the 'IO' monad and called
+at some point, directly or indirectly, from @Main.main@.
+
+'IO' is a monad, so 'IO' actions can be combined using either the do-notation
+or the '>>' and '>>=' operations from the 'Monad' class.
+-}
 newtype IO a = IO (State# RealWorld -> (# State# RealWorld, a #))
 
 unIO :: IO a -> (State# RealWorld -> (# State# RealWorld, a #))
@@ -78,38 +131,172 @@ bindIO (IO m) k = IO ( \ s ->
     (# new_s, a #) -> unIO (k a) new_s
   )
 
+thenIO :: IO a -> IO b -> IO b
+thenIO (IO m) k = IO ( \ s ->
+  case m s of 
+    (# new_s, a #) -> unIO k new_s
+  )
+
 returnIO :: a -> IO a
 returnIO x = IO (\ s -> (# s, x #))
 
 -- ---------------------------------------------------------------------------
 -- Coercions between IO and ST
 
---stToIO        :: (forall s. ST s a) -> IO a
+-- | A monad transformer embedding strict state transformers in the 'IO'
+-- monad.  The 'RealWorld' parameter indicates that the internal state
+-- used by the 'ST' computation is a special one supplied by the 'IO'
+-- monad, and thus distinct from those used by invocations of 'runST'.
 stToIO       :: ST RealWorld a -> IO a
 stToIO (ST m) = IO m
 
 ioToST       :: IO a -> ST RealWorld a
 ioToST (IO m) = (ST m)
 
+-- This relies on IO and ST having the same representation modulo the
+-- constraint on the type of the state
+--
+unsafeIOToST        :: IO a -> ST s a
+unsafeIOToST (IO io) = ST $ \ s -> (unsafeCoerce# io) s
+
+unsafeSTToIO :: ST s a -> IO a
+unsafeSTToIO (ST m) = IO (unsafeCoerce# m)
+
 -- ---------------------------------------------------------------------------
 -- Unsafe IO operations
 
-{-# NOINLINE unsafePerformIO #-}
+{-|
+This is the \"back door\" into the 'IO' monad, allowing
+'IO' computation to be performed at any time.  For
+this to be safe, the 'IO' computation should be
+free of side effects and independent of its environment.
+
+If the I\/O computation wrapped in 'unsafePerformIO'
+performs side effects, then the relative order in which those side
+effects take place (relative to the main I\/O trunk, or other calls to
+'unsafePerformIO') is indeterminate.  You have to be careful when 
+writing and compiling modules that use 'unsafePerformIO':
+
+  * Use @{\-\# NOINLINE foo \#-\}@ as a pragma on any function @foo@
+       that calls 'unsafePerformIO'.  If the call is inlined,
+       the I\/O may be performed more than once.
+
+  * Use the compiler flag @-fno-cse@ to prevent common sub-expression
+       elimination being performed on the module, which might combine
+       two side effects that were meant to be separate.  A good example
+       is using multiple global variables (like @test@ in the example below).
+
+  * Make sure that the either you switch off let-floating, or that the 
+       call to 'unsafePerformIO' cannot float outside a lambda.  For example, 
+       if you say:
+       @
+          f x = unsafePerformIO (newIORef [])
+       @
+       you may get only one reference cell shared between all calls to @f@.
+       Better would be
+       @
+          f x = unsafePerformIO (newIORef [x])
+       @
+       because now it can't float outside the lambda.
+
+It is less well known that
+'unsafePerformIO' is not type safe.  For example:
+
+>     test :: IORef [a]
+>     test = unsafePerformIO $ newIORef []
+>     
+>     main = do
+>            writeIORef test [42]
+>            bang <- readIORef test
+>            print (bang :: [Char])
+
+This program will core dump.  This problem with polymorphic references
+is well known in the ML community, and does not arise with normal
+monadic use of references.  There is no easy way to make it impossible
+once you use 'unsafePerformIO'.  Indeed, it is
+possible to write @coerce :: a -> b@ with the
+help of 'unsafePerformIO'.  So be careful!
+-}
 unsafePerformIO        :: IO a -> a
-unsafePerformIO (IO m) = case m realWorld# of (# _, r #)   -> r
-
-{-# NOINLINE unsafeInterleaveIO #-}
+unsafePerformIO m = unsafeDupablePerformIO (noDuplicate >> m)
+
+{-| 
+This version of 'unsafePerformIO' is slightly more efficient,
+because it omits the check that the IO is only being performed by a
+single thread.  Hence, when you write 'unsafeDupablePerformIO',
+there is a possibility that the IO action may be performed multiple
+times (on a multiprocessor), and you should therefore ensure that
+it gives the same results each time.
+-}
+{-# NOINLINE unsafeDupablePerformIO #-}
+unsafeDupablePerformIO :: IO a -> a
+unsafeDupablePerformIO (IO m) = lazy (case m realWorld# of (# _, r #) -> r)
+
+-- Why do we NOINLINE unsafeDupablePerformIO?  See the comment with
+-- GHC.ST.runST.  Essentially the issue is that the IO computation
+-- inside unsafePerformIO must be atomic: it must either all run, or
+-- not at all.  If we let the compiler see the application of the IO
+-- to realWorld#, it might float out part of the IO.
+
+-- Why is there a call to 'lazy' in unsafeDupablePerformIO?
+-- If we don't have it, the demand analyser discovers the following strictness
+-- for unsafeDupablePerformIO:  C(U(AV))
+-- But then consider
+--     unsafeDupablePerformIO (\s -> let r = f x in 
+--                            case writeIORef v r s of (# s1, _ #) ->
+--                            (# s1, r #)
+-- The strictness analyser will find that the binding for r is strict,
+-- (becuase of uPIO's strictness sig), and so it'll evaluate it before 
+-- doing the writeIORef.  This actually makes tests/lib/should_run/memo002
+-- get a deadlock!  
+--
+-- Solution: don't expose the strictness of unsafeDupablePerformIO,
+--          by hiding it with 'lazy'
+
+{-|
+'unsafeInterleaveIO' allows 'IO' computation to be deferred lazily.
+When passed a value of type @IO a@, the 'IO' will only be performed
+when the value of the @a@ is demanded.  This is used to implement lazy
+file reading, see 'System.IO.hGetContents'.
+-}
+{-# INLINE unsafeInterleaveIO #-}
 unsafeInterleaveIO :: IO a -> IO a
-unsafeInterleaveIO (IO m)
+unsafeInterleaveIO m = unsafeDupableInterleaveIO (noDuplicate >> m)
+
+-- We believe that INLINE on unsafeInterleaveIO is safe, because the
+-- state from this IO thread is passed explicitly to the interleaved
+-- IO, so it cannot be floated out and shared.
+
+{-# INLINE unsafeDupableInterleaveIO #-}
+unsafeDupableInterleaveIO :: IO a -> IO a
+unsafeDupableInterleaveIO (IO m)
   = IO ( \ s -> let
                   r = case m s of (# _, res #) -> res
                in
                (# s, r #))
 
+{-| 
+Ensures that the suspensions under evaluation by the current thread
+are unique; that is, the current thread is not evaluating anything
+that is also under evaluation by another thread that has also executed
+'noDuplicate'.
+
+This operation is used in the definition of 'unsafePerformIO' to
+prevent the IO action from being executed multiple times, which is usually
+undesirable.
+-}
+noDuplicate :: IO ()
+noDuplicate = IO $ \s -> case noDuplicate# s of s' -> (# s', () #)
+
 -- ---------------------------------------------------------------------------
 -- Handle type
 
 data MVar a = MVar (MVar# RealWorld a)
+{- ^
+An 'MVar' (pronounced \"em-var\") is a synchronising variable, used
+for communication between concurrent threads.  It can be thought of
+as a a box, which may be empty or full.
+-}
 
 -- pull in Eq (Mvar a) too, to avoid GHC.Conc being an orphan-instance module
 instance Eq (MVar a) where
@@ -129,11 +316,51 @@ instance Eq (MVar a) where
 -- Note: when a Handle is garbage collected, we want to flush its buffer
 -- and close the OS file handle, so as to free up a (precious) resource.
 
+-- | Haskell defines operations to read and write characters from and to files,
+-- represented by values of type @Handle@.  Each value of this type is a
+-- /handle/: a record used by the Haskell run-time system to /manage/ I\/O
+-- with file system objects.  A handle has at least the following properties:
+-- 
+--  * whether it manages input or output or both;
+--
+--  * whether it is /open/, /closed/ or /semi-closed/;
+--
+--  * whether the object is seekable;
+--
+--  * whether buffering is disabled, or enabled on a line or block basis;
+--
+--  * a buffer (whose length may be zero).
+--
+-- Most handles will also have a current I\/O position indicating where the next
+-- input or output operation will occur.  A handle is /readable/ if it
+-- manages only input or both input and output; likewise, it is /writable/ if
+-- it manages only output or both input and output.  A handle is /open/ when
+-- first allocated.
+-- Once it is closed it can no longer be used for either input or output,
+-- though an implementation cannot re-use its storage while references
+-- remain to it.  Handles are in the 'Show' and 'Eq' classes.  The string
+-- produced by showing a handle is system dependent; it should include
+-- enough information to identify the handle for debugging.  A handle is
+-- equal according to '==' only to itself; no attempt
+-- is made to compare the internal state of different handles for equality.
+--
+-- GHC note: a 'Handle' will be automatically closed when the garbage
+-- collector detects that it has become unreferenced by the program.
+-- However, relying on this behaviour is not generally recommended:
+-- the garbage collector is unpredictable.  If possible, use explicit
+-- an explicit 'hClose' to close 'Handle's when they are no longer
+-- required.  GHC does not currently attempt to free up file
+-- descriptors when they have run out, it is your responsibility to
+-- ensure that this doesn't happen.
+
 data Handle 
   = FileHandle                         -- A normal handle to a file
+       FilePath                        -- the file (invariant)
        !(MVar Handle__)
 
   | DuplexHandle                       -- A handle to a read/write stream
+       FilePath                        -- file for a FIFO, otherwise some
+                                       --   descriptive string.
        !(MVar Handle__)                -- The read side
        !(MVar Handle__)                -- The write side
 
@@ -142,20 +369,20 @@ data Handle
 --      seekable.
 
 instance Eq Handle where
- (FileHandle h1)     == (FileHandle h2)     = h1 == h2
- (DuplexHandle h1 _) == (DuplexHandle h2 _) = h1 == h2
+ (FileHandle _ h1)     == (FileHandle _ h2)     = h1 == h2
+ (DuplexHandle _ h1 _) == (DuplexHandle _ h2 _) = h1 == h2
  _ == _ = False 
 
-type FD = Int -- XXX ToDo: should be CInt
+type FD = CInt
 
 data Handle__
   = Handle__ {
       haFD         :: !FD,                  -- file descriptor
       haType        :: HandleType,          -- type (read/write/append etc.)
       haIsBin       :: Bool,                -- binary mode?
-      haIsStream    :: Bool,                -- is this a stream handle?
+      haIsStream    :: Bool,                -- Windows : is this a socket?
+                                             -- Unix    : is O_NONBLOCK set?
       haBufferMode  :: BufferMode,          -- buffer contains read/write data?
-      haFilePath    :: FilePath,            -- file name, possibly
       haBuffer     :: !(IORef Buffer),      -- the current buffer
       haBuffers     :: !(IORef BufferList),  -- spare buffers
       haOtherSide   :: Maybe (MVar Handle__) -- ptr to the write side of a 
@@ -247,70 +474,131 @@ isWritableHandleType WriteHandle     = True
 isWritableHandleType ReadWriteHandle = True
 isWritableHandleType _              = False
 
--- File names are specified using @FilePath@, a OS-dependent
--- string that (hopefully, I guess) maps to an accessible file/object.
+isReadWriteHandleType ReadWriteHandle{} = True
+isReadWriteHandleType _                 = False
+
+-- | File and directory names are values of type 'String', whose precise
+-- meaning is operating system dependent. Files can be opened, yielding a
+-- handle which can then be used to operate on the contents of that file.
 
 type FilePath = String
 
 -- ---------------------------------------------------------------------------
 -- Buffering modes
 
--- Three kinds of buffering are supported: line-buffering, 
+-- | Three kinds of buffering are supported: line-buffering, 
 -- block-buffering or no-buffering.  These modes have the following
--- effects. For output, items are written out from the internal
--- buffer according to the buffer mode:
+-- effects. For output, items are written out, or /flushed/,
+-- from the internal buffer according to the buffer mode:
 --
--- * line-buffering  the entire output buffer is written
---   out whenever a newline is output, the output buffer overflows, 
---   a flush is issued, or the handle is closed.
+--  * /line-buffering/: the entire output buffer is flushed
+--    whenever a newline is output, the buffer overflows, 
+--    a 'System.IO.hFlush' is issued, or the handle is closed.
 --
--- * block-buffering the entire output buffer is written out whenever 
---   it overflows, a flush is issued, or the handle
---   is closed.
+--  * /block-buffering/: the entire buffer is written out whenever it
+--    overflows, a 'System.IO.hFlush' is issued, or the handle is closed.
 --
--- * no-buffering output is written immediately, and never stored
---   in the output buffer.
+--  * /no-buffering/: output is written immediately, and never stored
+--    in the buffer.
 --
+-- An implementation is free to flush the buffer more frequently,
+-- but not less frequently, than specified above.
 -- The output buffer is emptied as soon as it has been written out.
-
--- Similarly, input occurs according to the buffer mode for handle {\em hdl}.
-
--- * line-buffering when the input buffer for the handle is not empty,
---   the next item is obtained from the buffer;
---   otherwise, when the input buffer is empty,
---   characters up to and including the next newline
---   character are read into the buffer.  No characters
---   are available until the newline character is
---   available.
 --
--- * block-buffering when the input buffer for the handle becomes empty,
---   the next block of data is read into this buffer.
+-- Similarly, input occurs according to the buffer mode for the handle:
 --
--- * no-buffering the next input item is read and returned.
-
+--  * /line-buffering/: when the buffer for the handle is not empty,
+--    the next item is obtained from the buffer; otherwise, when the
+--    buffer is empty, characters up to and including the next newline
+--    character are read into the buffer.  No characters are available
+--    until the newline character is available or the buffer is full.
+--
+--  * /block-buffering/: when the buffer for the handle becomes empty,
+--    the next block of data is read into the buffer.
+--
+--  * /no-buffering/: the next input item is read and returned.
+--    The 'System.IO.hLookAhead' operation implies that even a no-buffered
+--    handle may require a one-character buffer.
+--
+-- The default buffering mode when a handle is opened is
+-- implementation-dependent and may depend on the file system object
+-- which is attached to that handle.
 -- For most implementations, physical files will normally be block-buffered 
--- and terminals will normally be line-buffered. (the IO interface provides
--- operations for changing the default buffering of a handle tho.)
+-- and terminals will normally be line-buffered.
 
 data BufferMode  
- = NoBuffering | LineBuffering | BlockBuffering (Maybe Int)
+ = NoBuffering -- ^ buffering is disabled if possible.
+ | LineBuffering
+               -- ^ line-buffering should be enabled if possible.
+ | BlockBuffering (Maybe Int)
+               -- ^ block-buffering should be enabled if possible.
+               -- The size of the buffer is @n@ items if the argument
+               -- is 'Just' @n@ and is otherwise implementation-dependent.
    deriving (Eq, Ord, Read, Show)
 
 -- ---------------------------------------------------------------------------
 -- IORefs
 
-newtype IORef a = IORef (STRef RealWorld a) deriving Eq
+-- |A mutable variable in the 'IO' monad
+newtype IORef a = IORef (STRef RealWorld a)
+
+-- explicit instance because Haddock can't figure out a derived one
+instance Eq (IORef a) where
+  IORef x == IORef y = x == y
 
+-- |Build a new 'IORef'
 newIORef    :: a -> IO (IORef a)
 newIORef v = stToIO (newSTRef v) >>= \ var -> return (IORef var)
 
+-- |Read the value of an 'IORef'
 readIORef   :: IORef a -> IO a
 readIORef  (IORef var) = stToIO (readSTRef var)
 
+-- |Write a new value into an 'IORef'
 writeIORef  :: IORef a -> a -> IO ()
 writeIORef (IORef var) v = stToIO (writeSTRef var v)
 
 -- ---------------------------------------------------------------------------
+-- | An 'IOArray' is a mutable, boxed, non-strict array in the 'IO' monad.  
+-- The type arguments are as follows:
+--
+--  * @i@: the index type of the array (should be an instance of 'Ix')
+--
+--  * @e@: the element type of the array.
+--
+-- 
+
+newtype IOArray i e = IOArray (STArray RealWorld i e)
+
+-- explicit instance because Haddock can't figure out a derived one
+instance Eq (IOArray i e) where
+  IOArray x == IOArray y = x == y
+
+-- |Build a new 'IOArray'
+newIOArray :: Ix i => (i,i) -> e -> IO (IOArray i e)
+{-# INLINE newIOArray #-}
+newIOArray lu init  = stToIO $ do {marr <- newSTArray lu init; return (IOArray marr)}
+
+-- | Read a value from an 'IOArray'
+unsafeReadIOArray  :: Ix i => IOArray i e -> Int -> IO e
+{-# INLINE unsafeReadIOArray #-}
+unsafeReadIOArray (IOArray marr) i = stToIO (unsafeReadSTArray marr i)
+
+-- | Write a new value into an 'IOArray'
+unsafeWriteIOArray :: Ix i => IOArray i e -> Int -> e -> IO ()
+{-# INLINE unsafeWriteIOArray #-}
+unsafeWriteIOArray (IOArray marr) i e = stToIO (unsafeWriteSTArray marr i e)
+
+-- | Read a value from an 'IOArray'
+readIOArray  :: Ix i => IOArray i e -> i -> IO e
+readIOArray (IOArray marr) i = stToIO (readSTArray marr i)
+
+-- | Write a new value into an 'IOArray'
+writeIOArray :: Ix i => IOArray i e -> i -> e -> IO ()
+writeIOArray (IOArray marr) i e = stToIO (writeSTArray marr i e)
+
+
+-- ---------------------------------------------------------------------------
 -- Show instance for Handles
 
 -- handle types are 'show'n when printing error msgs, so
@@ -328,68 +616,101 @@ instance Show HandleType where
       ReadWriteHandle   -> showString "read-writable"
 
 instance Show Handle where 
-  showsPrec p (FileHandle   h)   = showHandle p h False
-  showsPrec p (DuplexHandle _ h) = showHandle p h True
-   
-showHandle p h duplex =
-    let
-     -- (Big) SIGH: unfolded defn of takeMVar to avoid
-     -- an (oh-so) unfortunate module loop with GHC.Conc.
-     hdl_ = unsafePerformIO (IO $ \ s# ->
-            case h                 of { MVar h# ->
-            case takeMVar# h# s#   of { (# s2# , r #) -> 
-            case putMVar# h# r s2# of { s3# ->
-            (# s3#, r #) }}})
-
-     showType | duplex = showString "duplex (read-write)"
-             | otherwise = showsPrec p (haType hdl_)
-    in
-    showChar '{' . 
-    showHdl (haType hdl_) 
-           (showString "loc=" . showString (haFilePath hdl_) . showChar ',' .
-            showString "type=" . showType . showChar ',' .
-            showString "binary=" . showsPrec p (haIsBin hdl_) . showChar ',' .
-            showString "buffering=" . showBufMode (unsafePerformIO (readIORef (haBuffer hdl_))) (haBufferMode hdl_) . showString "}" )
-   where
-
-    showHdl :: HandleType -> ShowS -> ShowS
-    showHdl ht cont = 
-       case ht of
-        ClosedHandle  -> showsPrec p ht . showString "}"
-       _ -> cont
-       
-    showBufMode :: Buffer -> BufferMode -> ShowS
-    showBufMode buf bmo =
-      case bmo of
-        NoBuffering   -> showString "none"
-       LineBuffering -> showString "line"
-       BlockBuffering (Just n) -> showString "block " . showParen True (showsPrec p n)
-       BlockBuffering Nothing  -> showString "block " . showParen True (showsPrec p def)
-      where
-       def :: Int 
-       def = bufSize buf
+  showsPrec p (FileHandle   file _)   = showHandle file
+  showsPrec p (DuplexHandle file _ _) = showHandle file
+
+showHandle file = showString "{handle: " . showString file . showString "}"
 
 -- ------------------------------------------------------------------------
 -- 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
+-- 'Data.Dynamic.Dynamic' (see the section on Dynamic Exceptions:
+-- "Control.Exception\#DynamicExceptions").
 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 except for 'DivideByZero').
+  | 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: "Control.Exception\#AsynchronousExceptions").
+  | BlockedOnDeadMVar
+       -- ^The current thread was executing a call to
+       -- 'Control.Concurrent.MVar.takeMVar' that could never return,
+       -- because there are no other references to this 'MVar'.
+  | BlockedIndefinitely
+       -- ^The current thread was waiting to retry an atomic memory transaction
+       -- that could never become possible to complete because there are no other
+       -- threads referring to any of teh TVars involved.
+  | NestedAtomically
+       -- ^The runtime detected an attempt to nest one STM transaction
+       -- inside another one, presumably due to the use of 
+       -- 'unsafePeformIO' with 'atomically'.
+  | 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: "Control.Exception\#DynamicExceptions").
+  | 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.Exit.exitWith' (and
+       -- 'System.Exit.exitFailure').  The 'ExitCode' argument is the value passed 
+       -- to 'System.Exit.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
@@ -398,15 +719,38 @@ data ArithException
   | 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 'Control.Concurrent.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
@@ -447,9 +791,11 @@ instance Show Exception where
   showsPrec _ (RecConError err)                 = showString err
   showsPrec _ (RecUpdError err)                 = showString err
   showsPrec _ (AssertionFailed err)      = showString err
-  showsPrec _ (DynException _err)        = showString "unknown exception"
+  showsPrec _ (DynException err)         = showString "exception :: " . showsTypeRep (dynTypeRep err)
   showsPrec _ (AsyncException e)        = shows e
   showsPrec _ (BlockedOnDeadMVar)       = showString "thread blocked indefinitely"
+  showsPrec _ (BlockedIndefinitely)     = showString "thread blocked indefinitely"
+  showsPrec _ (NestedAtomically)        = showString "Control.Concurrent.STM.atomically was nested"
   showsPrec _ (NonTermination)           = showString "<<loop>>"
   showsPrec _ (Deadlock)                 = showString "<<deadlock>>"
 
@@ -469,53 +815,80 @@ instance Eq Exception where
   AsyncException e1   == AsyncException e2   = e1 == e2
   BlockedOnDeadMVar   == BlockedOnDeadMVar   = True
   NonTermination      == NonTermination      = True
+  NestedAtomically    == NestedAtomically    = True
   Deadlock            == Deadlock            = True
+  _                   == _                   = False
 
 -- -----------------------------------------------------------------------------
 -- The ExitCode type
 
--- The `ExitCode' type defines the exit codes that a program
--- can return.  `ExitSuccess' indicates successful termination;
--- and `ExitFailure code' indicates program failure
--- with value `code'.  The exact interpretation of `code'
--- is operating-system dependent.  In particular, some values of 
--- `code' may be prohibited (e.g. 0 on a POSIX-compliant system).
-
 -- We need it here because it is used in ExitException in the
 -- Exception datatype (above).
 
-data ExitCode = ExitSuccess | ExitFailure Int 
-                deriving (Eq, Ord, Read, Show)
+data ExitCode
+  = ExitSuccess        -- ^ indicates successful termination;
+  | ExitFailure Int
+               -- ^ indicates program failure with an exit code.
+               -- The exact interpretation of the code is
+               -- operating-system dependent.  In particular, some values
+               -- may be prohibited (e.g. 0 on a POSIX-compliant system).
+  deriving (Eq, Ord, Read, Show)
 
 -- --------------------------------------------------------------------------
 -- 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
 
-ioError         :: Exception -> IO a 
-ioError err    =  IO $ \s -> throw err s
+-- | A variant of 'throw' that can be used within the 'IO' monad.
+--
+-- Although 'throwIO' has a type that is an instance of the type of 'throw', the
+-- two functions are subtly different:
+--
+-- > throw e   `seq` x  ===> throw e
+-- > throwIO e `seq` x  ===> x
+--
+-- The first example will cause the exception @e@ to be raised,
+-- whereas the second one won\'t.  In fact, 'throwIO' will only cause
+-- an exception to be raised when it is used within the 'IO' monad.
+-- The 'throwIO' 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.
+throwIO         :: Exception -> IO a
+throwIO err    =  IO $ raiseIO# err
 
 ioException    :: IOException -> IO a
-ioException err =  IO $ \s -> throw (IOException err) s
+ioException err =  IO $ raiseIO# (IOException err)
+
+-- | Raise an 'IOError' in the 'IO' monad.
+ioError         :: IOError -> IO a 
+ioError                =  ioException
 
 -- ---------------------------------------------------------------------------
 -- IOError type
 
--- A value @IOError@ encode errors occurred in the @IO@ monad.
--- An @IOError@ records a more specific error type, a descriptive
+-- | The Haskell 98 type for exceptions in the 'IO' monad.
+-- Any I\/O operation may raise an 'IOError' instead of returning a result.
+-- For a more general type of exception, including also those that arise
+-- in pure code, see 'Control.Exception.Exception'.
+--
+-- In Haskell 98, this is an opaque type.
+type IOError = IOException
+
+-- |Exceptions that occur in the @IO@ monad.
+-- An @IOException@ records a more specific error type, a descriptive
 -- string and maybe the handle that was used when the error was
 -- flagged.
-
-type IOError = Exception
-
 data IOException
  = IOError {
      ioe_handle   :: Maybe Handle,   -- the handle used by the action flagging 
                                     -- the error.
      ioe_type     :: IOErrorType,    -- what it was.
      ioe_location :: String,        -- location.
-     ioe_descr    :: String,         -- error type specific information.
+     ioe_description :: String,      -- error type specific information.
      ioe_filename :: Maybe FilePath  -- filename the error is related to.
    }
 
@@ -523,6 +896,7 @@ instance Eq IOException where
   (IOError h1 e1 loc1 str1 fn1) == (IOError h2 e2 loc2 str2 fn2) = 
     e1==e2 && str1==str2 && h1==h2 && loc1==loc2 && fn1==fn2
 
+-- | An abstract type that contains a value for each variant of 'IOError'.
 data IOErrorType
   -- Haskell 98:
   = AlreadyExists
@@ -551,7 +925,7 @@ instance Eq IOErrorType where
    x == y = 
      case x of
        DynIOError{} -> False -- from a strictness POV, compatible with a derived Eq inst?
-       _ -> getTag# x ==# getTag# y
+       _ -> getTag x ==# getTag y
  
 instance Show IOErrorType where
   showsPrec _ e =
@@ -578,25 +952,38 @@ instance Show IOErrorType where
       UnsupportedOperation -> "unsupported operation"
       DynIOError{}      -> "unknown IO error"
 
+-- | Construct an 'IOError' value with a string describing the error.
+-- The 'fail' method of the 'IO' instance of the 'Monad' class raises a
+-- 'userError', thus:
+--
+-- > instance Monad IO where 
+-- >   ...
+-- >   fail s = ioError (userError s)
+--
 userError       :: String  -> IOError
-userError str  =  IOException (IOError Nothing UserError "" str Nothing)
+userError str  =  IOError Nothing UserError "" str Nothing
 
 -- ---------------------------------------------------------------------------
 -- Showing IOErrors
 
 instance Show IOException where
     showsPrec p (IOError hdl iot loc s fn) =
-      showsPrec p iot .
+      (case fn of
+        Nothing -> case hdl of
+                       Nothing -> id
+                       Just h  -> showsPrec p h . showString ": "
+        Just name -> showString name . showString ": ") .
       (case loc of
          "" -> id
-        _  -> showString "\nAction: " . showString loc) .
-      (case hdl of
-        Nothing -> id
-       Just h  -> showString "\nHandle: " . showsPrec p h) .
+        _  -> showString loc . showString ": ") .
+      showsPrec p iot . 
       (case s of
         "" -> id
-        _  -> showString "\nReason: " . showString s) .
-      (case fn of
-        Nothing -> id
-        Just name -> showString "\nFile: " . showString name)
+        _  -> showString " (" . showString s . showString ")")
+
+-- -----------------------------------------------------------------------------
+-- IOMode type
+
+data IOMode      =  ReadMode | WriteMode | AppendMode | ReadWriteMode
+                    deriving (Eq, Ord, Ix, Enum, Read, Show)
 \end{code}