Fix comment
[ghc.git] / libraries / base / GHC / IO.hs
index 0744e3a..8459db6 100644 (file)
@@ -3,6 +3,7 @@
            , BangPatterns
            , RankNTypes
            , MagicHash
+           , ScopedTypeVariables
            , UnboxedTuples
   #-}
 {-# OPTIONS_GHC -funbox-strict-fields #-}
@@ -33,7 +34,7 @@ module GHC.IO (
 
         FilePath,
 
-        catchException, catchAny, throwIO,
+        catch, catchException, catchAny, throwIO,
         mask, mask_, uninterruptibleMask, uninterruptibleMask_,
         MaskingState(..), getMaskingState,
         unsafeUnmask, interruptible,
@@ -61,10 +62,10 @@ system.  The following list may or may not be exhaustive:
 
 Compiler  - types of various primitives in PrimOp.hs
 
-RTS       - forceIO (StgMiscClosures.hc)
+RTS       - forceIO (StgStartup.cmm)
           - catchzh_fast, (un)?blockAsyncExceptionszh_fast, raisezh_fast
-            (Exceptions.hc)
-          - raiseAsync (Schedule.c)
+            (Exception.cmm)
+          - raiseAsync (RaiseAsync.c)
 
 Prelude   - GHC.IO.hs, and several other places including
             GHC.Exception.hs.
@@ -113,7 +114,7 @@ type FilePath = String
 -- Primitive catch and throwIO
 
 {-
-catchException used to handle the passing around of the state to the
+catchException/catch used to handle the passing around of the state to the
 action and the handler.  This turned out to be a bad idea - it meant
 that we had to wrap both arguments in thunks so they could be entered
 as normal (remember IO returns an unboxed pair...).
@@ -123,7 +124,7 @@ Now catch# has type
     catch# :: IO a -> (b -> IO a) -> IO a
 
 (well almost; the compiler doesn't know about the IO newtype so we
-have to work around that in the definition of catchException below).
+have to work around that in the definition of catch below).
 -}
 
 -- | Catch an exception in the 'IO' monad.
@@ -132,25 +133,66 @@ have to work around that in the definition of catchException below).
 -- @catchException undefined b == _|_@. See #exceptions_and_strictness#
 -- for details.
 catchException :: Exception e => IO a -> (e -> IO a) -> IO a
-catchException (IO io) handler = IO $ catch# io handler'
+catchException !io handler = catch io handler
+
+-- | 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 (readFile f)
+-- >         (\e -> do let err = show (e :: IOException)
+-- >                   hPutStr stderr ("Warning: Couldn't open " ++ f ++ ": " ++ err)
+-- >                   return "")
+--
+-- Note that we have to give a type signature to @e@, or the program
+-- will not typecheck as the type is ambiguous. While it is possible
+-- to catch exceptions of any type, see the section \"Catching all
+-- exceptions\" (in "Control.Exception") for an explanation of the problems with doing so.
+--
+-- For catching exceptions in pure (non-'IO') expressions, see the
+-- function 'evaluate'.
+--
+-- Note that due to Haskell\'s unspecified evaluation order, an
+-- expression may throw one of several possible exceptions: consider
+-- the expression @(error \"urk\") + (1 \`div\` 0)@.  Does
+-- the expression throw
+-- @ErrorCall \"urk\"@, or @DivideByZero@?
+--
+-- The answer is \"it might throw either\"; the choice is
+-- non-deterministic. If you are catching any type of exception then you
+-- might catch either. If you are calling @catch@ with type
+-- @IO Int -> (ArithException -> IO Int) -> IO Int@ then the handler may
+-- get run with @DivideByZero@ as an argument, or an @ErrorCall \"urk\"@
+-- exception may be propogated further up. If you call it again, you
+-- might get a the opposite behaviour. This is ok, because 'catch' is an
+-- 'IO' computation.
+--
+catch   :: Exception e
+        => IO a         -- ^ The computation to run
+        -> (e -> IO a)  -- ^ Handler to invoke if an exception is raised
+        -> IO a
+-- See #exceptions_and_strictness#.
+catch (IO io) handler = IO $ catch# io handler'
     where handler' e = case fromException e of
                        Just e' -> unIO (handler e')
                        Nothing -> raiseIO# e
 
+
 -- | Catch any 'Exception' type in the 'IO' monad.
 --
 -- Note that this function is /strict/ in the action. That is,
--- @catchException undefined b == _|_@. See #exceptions_and_strictness# for
+-- @catchAny undefined b == _|_@. See #exceptions_and_strictness# for
 -- details.
 catchAny :: IO a -> (forall e . Exception e => e -> IO a) -> IO a
-catchAny (IO io) handler = IO $ catch# io handler'
+catchAny !(IO io) handler = IO $ catch# io handler'
     where handler' (SomeException e) = unIO (handler e)
 
-
+-- Using catchException here means that if `m` throws an
+-- 'IOError' /as an imprecise exception/, we will not catch
+-- it. No one should really be doing that anyway.
 mplusIO :: IO a -> IO a -> IO a
-mplusIO m n = m `catchIOError` \ _ -> n
-    where catchIOError :: IO a -> (IOError -> IO a) -> IO a
-          catchIOError = catchException
+mplusIO m n = m `catchException` \ (_ :: IOError) -> n
 
 -- | A variant of 'throw' that can only be used within the 'IO' monad.
 --
@@ -387,28 +429,20 @@ evaluate a = IO $ \s -> seq# a s -- NB. see #2273, #5129
 {- $exceptions_and_strictness
 
 Laziness can interact with @catch@-like operations in non-obvious ways (see,
-e.g. GHC Trac #11555). For instance, consider these subtly-different examples,
+e.g. GHC Trac #11555 and #13330). For instance, consider these subtly-different
+examples:
 
 > test1 = Control.Exception.catch (error "uh oh") (\(_ :: SomeException) -> putStrLn "it failed")
 >
 > test2 = GHC.IO.catchException (error "uh oh") (\(_ :: SomeException) -> putStrLn "it failed")
 
-While the first case is always guaranteed to print "it failed", the behavior of
-@test2@ may vary with optimization level.
-
-The unspecified behavior of @test2@ is due to the fact that GHC may assume that
-'catchException' (and the 'catch#' primitive operation which it is built upon)
-is strict in its first argument. This assumption allows the compiler to better
-optimize @catchException@ calls at the expense of deterministic behavior when
-the action may be bottom.
+While @test1@ will print "it failed", @test2@ will print "uh oh".
 
-Namely, the assumed strictness means that exceptions thrown while evaluating the
-action-to-be-executed may not be caught; only exceptions thrown during execution
-of the action will be handled by the exception handler.
+When using 'catchException', exceptions thrown while evaluating the
+action-to-be-executed will not be caught; only exceptions thrown during
+execution of the action will be handled by the exception handler.
 
 Since this strictness is a small optimization and may lead to surprising
 results, all of the @catch@ and @handle@ variants offered by "Control.Exception"
-are lazy in their first argument. If you are certain that that the action to be
-executed won't bottom in performance-sensitive code, you might consider using
-'GHC.IO.catchException' or 'GHC.IO.catchAny' for a small speed-up.
+use 'catch' rather than 'catchException'.
 -}