This library is the home for miscellaneous IO-related extensions.
fixIO allows recursive IO operations to be defined. The first argument to fixIO should be a function that takes its own output as an argument (sometimes called "tying the knot").
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 not type safe. For example:
test :: IORef [a] test = unsafePerformIO $ newIORef [] main = do writeIORef test [42] bang <- readIORef test print (bang :: [Char]) |
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.
data IORef -- instance of: Eq newIORef :: a -> IO (IORef a) readIORef :: IORef a -> IO a writeIORef :: IORef a -> a -> IO () modifyIORef :: IORef a -> (a -> a) -> IO () mkWeakIORef :: IORef a -> IO () -> IO (Weak (IORef a)) -- deprecated, use modifyIORef updateIORef :: IORef a -> (a -> a) -> IO () |
data IOArray -- instance of: Eq newIOArray :: Ix ix => (ix,ix) -> elt -> IO (IOArray ix elt) boundsIOArray :: Ix ix => IOArray ix elt -> (ix, ix) readIOArray :: Ix ix => IOArray ix elt -> ix -> IO elt writeIOArray :: Ix ix => IOArray ix elt -> ix -> elt -> IO () freezeIOArray :: Ix ix => IOArray ix elt -> IO (Array ix elt) thawIOArray :: Ix ix => Array ix elt -> IO (IOArray ix elt) unsafeFreezeIOArray :: Ix ix => IOArray ix elt -> IO (Array ix elt) unsafeThawIOArray :: Ix ix => Array ix elt -> IO (IOArray ix elt) |
Note: unsafeFreezeIOArray and unsafeThawIOArray are not provided by Hugs.
data IOModeEx = BinaryMode IOMode | TextMode IOMode deriving (Eq, Read, Show) openFileEx :: FilePath -> IOModeEx -> IO Handle hSetBinaryMode :: Handle -> Bool -> IO Bool |
GHC's implementation of the IO library distinguishes between binary- and text-mode files. This unfortunate hack is imposed on us by the need to support Win32 platforms.
On Win32, files opened in text mode are subject to CR-LF translation. When reading a handle in text mode, CR-LF sequences in the physical file are translated into lone LFs in the stream presented to the Haskell program. Writes to a text mode handle are subject to the inverse transformation.
On Unix platforms there is no such translation. What you get is exactly the contents of the file, and vice versa.
Unfortunately this behaviour makes it difficult to correctly implement file-positioning operations in text mode on Win32. If you want to use such operations, you must first place the handle in binary mode. Failure to do so results in IO exceptions being raised. This applies only to Win32, and not to any other platforms. If your programs use seek operations and you want them to be portable between Unix and Win32, you need to ensure the relevant handles are in binary mode.
You can get hold of a binary-mode file handle one of two ways. Either open the file with openFileEx, which allows the mode to be specified. Or, if you already have an open handle, use hSetBinaryMode to change its mode.
Also as a result of this, note that on Win32 there are also several operations which, whist still allowed, may give different results in text mode than their Unix counterparts. These are: changing buffering modes of a handle (hSetBuffering), and writing to a read-write handle. In both cases, the read-buffer associated with the handle needs to be flushed, and, due to the Win32 text mode translation, the resulting physical file position following the flush may be wrong.
This issue of seeking in the presence of a non-identity transform between file and buffer contents will need to be revisited when the library is re-done to properly support Unicode. The present arrangement is the least-worst kludge we could come up with at present.
hGetBuf :: Handle -> Addr -> Int -> IO Int hPutBuf :: Handle -> Addr -> Int -> IO () |
These functions read and write chunks of data to/from a handle. They will return only when either the full buffer has been transfered, or the end of file is reached (in the case of hGetBuf.
hGetBufBA :: Handle -> MutableByteArray RealWorld a -> Int -> IO Int hPutBufBA :: Handle -> MutableByteArray RealWorld a -> Int -> IO () |
These functions mirror the previous two functions, but operate on MutableByteArrays instead of Addrs. This may be more convenient and/or faster, depending on the circumstances.
hIsTerminalDevice :: Handle -> IO Bool hSetEcho :: Handle -> Bool -> IO () hGetEcho :: Handle -> IO Bool |
withHandleFor :: Handle -> Handle -> IO a -> IO a withStdout :: Handle -> IO a -> IO a withStdin :: Handle -> IO a -> IO a withStderr :: Handle -> IO a -> IO a |
trace :: String -> a -> a |
When called, trace prints the string in its first argument to standard error, before returning the second argument as its result. The trace function is not referentially transparent, and should only be used for debugging, or for monitoring execution. Some implementations of trace may decorate the string that's output to indicate that you're tracing.
trace is implemented using unsafePerformIO.
The IO module provides several predicates over the IOError type, such as isEOFError, isDoesNotExistError, and so on. Here we define an extended set of these predicates, taking into account more types of error:
isHardwareFault :: IOError -> Bool isInappropriateType :: IOError -> Bool isInterrupted :: IOError -> Bool isInvalidArgument :: IOError -> Bool isOtherError :: IOError -> Bool isProtocolError :: IOError -> Bool isResourceVanished :: IOError -> Bool isSystemError :: IOError -> Bool isTimeExpired :: IOError -> Bool isUnsatisfiedConstraints :: IOError -> Bool isUnsupportedOperation :: IOError -> Bool isDynIOError :: IOError -> Bool |
unsafePtrEq :: a -> a -> Bool slurpFile :: FilePath -> IO (Addr, Int) hConnectTo :: Handle -> Handle -> IO () performGC :: IO () freeHaskellFunctionPtr :: Addr -> IO () getDynIOError :: IOError -> Maybe Dynamic.Dynamic |
performGC triggers an immediate garbage collection
unsafePtrEq compares two values for pointer equality without evaluating them. The results are not referentially transparent and may vary significantly from one compiler to another or in the face of semantics-preserving program changes. However, pointer equality is useful in creating a number of referentially transparent constructs such as this simplified memoisation function:
> cache :: (a -> b) -> (a -> b) > cache f = \x -> unsafePerformIO (check x) > where > ref = unsafePerformIO (newIORef (error "cache", error "cache")) > check x = readIORef ref >>= \ (x',a) -> > if x `unsafePtrEq` x' then > return a > else > let a = f x in > writeIORef ref (x, a) >> > return a |
getDynIOError takes an IOError as argument. If it is a dynamic IO error, it returns Just d, where d is the dynamic value. Of (some) use by library providers to provide their own IOError types.