module GHC.IOBase 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
--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 #))
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.
-
-However, it is less well known that
+'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]
'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 'IO.hGetContents'.
+file reading, see 'System.IO.hGetContents'.
-}
{-# NOINLINE unsafeInterleaveIO #-}
unsafeInterleaveIO :: IO a -> IO a
-- |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'.
+-- 'Dynamic' (see the section on Dynamic Exceptions: "Control.Exception\#DynamicExceptions").
data Exception
= ArithException ArithException
-- ^Exceptions raised by arithmetic
-- operations. (NOTE: GHC currently does not throw
- -- 'ArithException's).
+ -- 'ArithException's except for 'DivideByZero').
| ArrayException ArrayException
-- ^Exceptions raised by array-related
-- operations. (NOTE: GHC currently does not throw
-- fails. The 'String' argument contains the
-- location of the assertion in the source program.
| AsyncException AsyncException
- -- ^Asynchronous exceptions (see section on Asynchronous Exceptions).
+ -- ^Asynchronous exceptions (see section on Asynchronous Exceptions: "Control.Exception\#AsynchronousExceptions").
| BlockedOnDeadMVar
-- ^The current thread was executing a call to
-- 'takeMVar' that could never return, because there are no other
-- 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).
+ -- ^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
BlockedOnDeadMVar == BlockedOnDeadMVar = True
NonTermination == NonTermination = True
Deadlock == Deadlock = True
+ _ == _ = False
-- -----------------------------------------------------------------------------
-- The ExitCode type
-- | 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
+-- Although 'throwIO' 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 ()
+-- > throwIO 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
+-- 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 'ioError' variant should be used in preference to 'throw' to
+-- 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.
-ioError :: Exception -> IO a
-ioError err = IO $ \s -> throw err s
+throwIO :: Exception -> IO a
+throwIO err = IO $ \s -> throw err s
ioException :: IOException -> IO a
ioException err = IO $ \s -> throw (IOException err) s
+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.
+-- 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
DynIOError{} -> "unknown IO error"
userError :: String -> IOError
-userError str = IOException (IOError Nothing UserError "" str Nothing)
+userError str = IOError Nothing UserError "" str Nothing
-- ---------------------------------------------------------------------------
-- Showing IOErrors
(case fn of
Nothing -> id
Just name -> showString "\nFile: " . showString name)
+
+-- -----------------------------------------------------------------------------
+-- IOMode type
+
+data IOMode = ReadMode | WriteMode | AppendMode | ReadWriteMode
+ deriving (Eq, Ord, Ix, Enum, Read, Show)
\end{code}