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
-- Unsafe IO operations
{-|
-This is the "back door" into the 'IO' monad, allowing
+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.
-
-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
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) deriving Eq
+
+-- |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
-- 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: "Control.Exception\#DynamicExceptions").
---
--- For backwards compatibility with Haskell 98, 'IOError' is a type synonym
--- for 'Exception'.
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
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
-- 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.
}
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 =
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}