[project @ 2002-05-27 14:31:06 by simonmar]
authorsimonmar <unknown>
Mon, 27 May 2002 14:31:08 +0000 (14:31 +0000)
committersimonmar <unknown>
Mon, 27 May 2002 14:31:08 +0000 (14:31 +0000)
Document Control.Exception and Data.Dynamic

Control/Exception.hs
Data/Dynamic.hs
GHC/Exception.lhs
GHC/IOBase.lhs
GHC/Read.lhs

index 8a66e97..5231db4 100644 (file)
@@ -8,31 +8,49 @@
 -- 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
@@ -42,34 +60,44 @@ module Control.Exception (
        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__
@@ -104,35 +132,118 @@ INSTANCE_TYPEABLE0(AsyncException,asyncExceptionTc,"AsyncException")
 -----------------------------------------------------------------------------
 -- 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
@@ -143,23 +254,32 @@ tryJust p a = do
                        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
@@ -172,6 +292,11 @@ catchDyn m k = catchException m handle
 -----------------------------------------------------------------------------
 -- 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
@@ -204,7 +329,30 @@ userErrors _ = Nothing
 -----------------------------------------------------------------------------
 -- 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 
@@ -215,9 +363,14 @@ bracket before after thing =
     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 
@@ -227,5 +380,98 @@ a `finally` sequel =
     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
index 4c44988..bf83db5 100644 (file)
 -- 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 ",,")
@@ -85,9 +81,16 @@ unsafeCoerce = unsafeCoerce#
 
 #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
@@ -100,8 +103,10 @@ 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 )
 
@@ -122,7 +127,8 @@ instance Show TypeRep where
      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
@@ -131,33 +137,52 @@ 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
@@ -175,7 +200,21 @@ isTupleTyCon _                    = False
 -- 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)
@@ -201,9 +240,12 @@ showTuple (TyCon _ str) args = showChar '(' . go str args
   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
 
@@ -223,6 +265,10 @@ dynApp f x = case dynApply f x of
                                "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
index 7979d4d..5822ea8 100644 (file)
@@ -109,17 +109,27 @@ bracket_ before after m = do
 %*********************************************************
 
 \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
index 608d2b1..1497ec9 100644 (file)
@@ -429,24 +429,87 @@ showHandle p h duplex =
 -- ------------------------------------------------------------------------
 -- 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
@@ -455,15 +518,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 '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
@@ -547,9 +633,26 @@ data ExitCode = ExitSuccess | ExitFailure Int
 -- --------------------------------------------------------------------------
 -- 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
 
index acc7ea2..b7b6965 100644 (file)
@@ -120,6 +120,8 @@ readList__ readx
 ------------------------------------------------------------------------
 -- 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)]
 
 ------------------------------------------------------------------------