From 1172e0e4b9640aa96095e31bcdc854cc55b54e34 Mon Sep 17 00:00:00 2001 From: ross Date: Sat, 30 Aug 2003 12:26:58 +0000 Subject: [PATCH] [project @ 2003-08-30 12:26:56 by ross] docs for System.IO.Error --- GHC/Exception.lhs | 18 ++++++ GHC/IOBase.lhs | 16 ++++- Prelude.hs | 16 ++++- System/IO/Error.hs | 174 ++++++++++++++++++++++++++++++++++++++++------------ 4 files changed, 181 insertions(+), 43 deletions(-) diff --git a/GHC/Exception.lhs b/GHC/Exception.lhs index a98ca19..08f5e97 100644 --- a/GHC/Exception.lhs +++ b/GHC/Exception.lhs @@ -47,6 +47,24 @@ have to work around that in the definition of catchException below). catchException :: IO a -> (Exception -> IO a) -> IO a catchException (IO m) k = IO $ \s -> catch# m (\ex -> unIO (k ex)) s +-- | The 'catch' function establishes a handler that receives any 'IOError' +-- raised in the action protected by 'catch'. An 'IOError' is caught by +-- the most recent handler established by 'catch'. These handlers are +-- not selective: all 'IOError's are caught. Exception propagation +-- must be explicitly provided in a handler by re-raising any unwanted +-- exceptions. For example, in +-- +-- > f = catch g (\e -> if IO.isEOFError e then return [] else ioError e) +-- +-- the function @f@ returns @[]@ when an end-of-file exception +-- (cf. 'System.IO.Error.isEOFError') occurs in @g@; otherwise, the +-- exception is propagated to the next outer handler. +-- +-- When an exception propagates outside the main program, the Haskell +-- system prints the associated 'IOError' value and exits the program. +-- +-- Non-I\/O exceptions are not caught by this variant; to catch all +-- exceptions, use 'Control.Exception.catch' from "Control.Exception". catch :: IO a -> (IOError -> IO a) -> IO a catch m k = catchException m handler where handler (IOException err) = k err diff --git a/GHC/IOBase.lhs b/GHC/IOBase.lhs index 84a2d84..c25c69e 100644 --- a/GHC/IOBase.lhs +++ b/GHC/IOBase.lhs @@ -743,13 +743,18 @@ throwIO err = IO $ raiseIO# err ioException :: IOException -> IO a ioException err = IO $ raiseIO# (IOException err) +-- | Raise an 'IOError' in the 'IO' monad. ioError :: IOError -> IO a ioError = ioException -- --------------------------------------------------------------------------- -- IOError type --- | The Haskell 98 type for exceptions in the @IO@ monad. +-- | The Haskell 98 type for exceptions in the 'IO' monad. +-- Any I\/O operation may raise an 'IOError' instead of returning a result. +-- For a more general type of exception, including also those that arise +-- in pure code, see 'Control.Exception.Exception'. +-- -- In Haskell 98, this is an opaque type. type IOError = IOException @@ -771,6 +776,7 @@ instance Eq IOException where (IOError h1 e1 loc1 str1 fn1) == (IOError h2 e2 loc2 str2 fn2) = e1==e2 && str1==str2 && h1==h2 && loc1==loc2 && fn1==fn2 +-- | An abstract type that contains a value for each variant of 'IOError'. data IOErrorType -- Haskell 98: = AlreadyExists @@ -826,6 +832,14 @@ instance Show IOErrorType where UnsupportedOperation -> "unsupported operation" DynIOError{} -> "unknown IO error" +-- | Construct an 'IOError' value with a string describing the error. +-- The 'fail' method of the 'IO' instance of the 'Monad' class raises a +-- 'userError', thus: +-- +-- > instance Monad IO where +-- > ... +-- > fail s = ioError (userError s) +-- userError :: String -> IOError userError str = IOError Nothing UserError "" str Nothing diff --git a/Prelude.hs b/Prelude.hs index 31aa6b6..7ad6355 100644 --- a/Prelude.hs +++ b/Prelude.hs @@ -75,14 +75,24 @@ module Prelude ( reads, shows, read, lex, showChar, showString, readParen, showParen, - -- * Simple I\/O operations - ioError, userError, catch, - FilePath, IOError, + -- * Basic Input and output + -- ** Simple I\/O operations + -- All I/O functions defined here are character oriented. The + -- treatment of the newline character will vary on different systems. + -- For example, two characters of input, return and linefeed, may + -- read as a single newline character. These functions cannot be + -- used portably for binary I/O. + -- *** Output functions putChar, putStr, putStrLn, print, + -- *** Input functions getChar, getLine, getContents, interact, + -- *** Files + FilePath, readFile, writeFile, appendFile, readIO, readLn, + -- ** Exception handling in the I\/O monad + IOError, ioError, userError, catch, -- * Monads Monad((>>=), (>>), return, fail), diff --git a/System/IO/Error.hs b/System/IO/Error.hs index 14e29fb..7250ef4 100644 --- a/System/IO/Error.hs +++ b/System/IO/Error.hs @@ -15,13 +15,10 @@ ----------------------------------------------------------------------------- module System.IO.Error ( - IOError, -- abstract - IOErrorType, -- abstract - catch, -- :: IO a -> (IOError -> IO a) -> IO a - try, -- :: IO a -> IO (Either IOError a) + -- * I\/O errors + IOError, -- = IOException - ioError, -- :: IOError -> IO a userError, -- :: String -> IOError #ifndef __NHC__ @@ -30,10 +27,36 @@ module System.IO.Error ( annotateIOError, -- :: IOError -> String -> Maybe Handle -- -> Maybe FilePath -> IOError +#endif - modifyIOError, -- :: (IOError -> IOError) -> IO a -> IO a + -- ** Classifying I\/O errors + isAlreadyExistsError, -- :: IOError -> Bool + isDoesNotExistError, + isAlreadyInUseError, + isFullError, + isEOFError, + isIllegalOperation, + isPermissionError, + isUserError, + + -- ** Attributes of I\/O errors +#ifndef __NHC__ + ioeGetErrorType, -- :: IOError -> IOErrorType +#endif + ioeGetErrorString, -- :: IOError -> String + ioeGetHandle, -- :: IOError -> Maybe Handle + ioeGetFileName, -- :: IOError -> Maybe FilePath + +#ifndef __NHC__ + ioeSetErrorType, -- :: IOError -> IOErrorType -> IOError + ioeSetErrorString, -- :: IOError -> String -> IOError + ioeSetHandle, -- :: IOError -> Handle -> IOError + ioeSetFileName, -- :: IOError -> FilePath -> IOError #endif + -- * Types of I\/O error + IOErrorType, -- abstract + alreadyExistsErrorType, -- :: IOErrorType doesNotExistErrorType, alreadyInUseErrorType, @@ -43,6 +66,7 @@ module System.IO.Error ( permissionErrorType, userErrorType, + -- ** 'IOErrorType' predicates isAlreadyExistsErrorType, -- :: IOErrorType -> Bool isDoesNotExistErrorType, isAlreadyInUseErrorType, @@ -52,27 +76,15 @@ module System.IO.Error ( isPermissionErrorType, isUserErrorType, - isAlreadyExistsError, -- :: IOError -> Bool - isDoesNotExistError, - isAlreadyInUseError, - isFullError, - isEOFError, - isIllegalOperation, - isPermissionError, - isUserError, + -- * Throwing and catching I\/O errors -#ifndef __NHC__ - ioeGetErrorType, -- :: IOError -> IOErrorType -#endif - ioeGetErrorString, -- :: IOError -> String - ioeGetHandle, -- :: IOError -> Maybe Handle - ioeGetFileName, -- :: IOError -> Maybe FilePath + ioError, -- :: IOError -> IO a + + catch, -- :: IO a -> (IOError -> IO a) -> IO a + try, -- :: IO a -> IO (Either IOError a) #ifndef __NHC__ - ioeSetErrorType, -- :: IOError -> IOErrorType -> IOError - ioeSetErrorString, -- :: IOError -> String -> IOError - ioeSetHandle, -- :: IOError -> Handle -> IOError - ioeSetFileName, -- :: IOError -> FilePath -> IOError + modifyIOError, -- :: (IOError -> IOError) -> IO a -> IO a #endif ) where @@ -112,10 +124,11 @@ import IO --import Control.Monad (MonadPlus(mplus)) #endif --- | The construct @try comp@ exposes IO errors which occur within a +-- | The construct 'try' @comp@ exposes IO errors which occur within a -- computation, and which are not fully handled. --- Other exceptions are not caught by this variant; --- to catch all exceptions, use @try@ from "Control.Exception". +-- +-- Non-I\/O exceptions are not caught by this variant; to catch all +-- exceptions, use 'Control.Exception.try' from "Control.Exception". #ifndef __NHC__ try :: IO a -> IO (Either IOError a) @@ -128,6 +141,10 @@ try f = catch (do r <- f -- ----------------------------------------------------------------------------- -- Constructing an IOError +-- | Construct an 'IOError' of the given type where the second argument +-- describes the error location and the third and fourth argument +-- contain the file handle and file path of the file involved in the +-- error if applicable. mkIOError :: IOErrorType -> String -> Maybe Handle -> Maybe FilePath -> IOError mkIOError t location maybe_hdl maybe_filename = IOError{ ioe_type = t, @@ -157,17 +174,50 @@ mkIOError t location maybe_hdl maybe_filename = -- ----------------------------------------------------------------------------- -- IOErrorType -isAlreadyExistsError, isDoesNotExistError, isAlreadyInUseError, - isFullError, isEOFError, isIllegalOperation, isPermissionError, - isUserError :: IOError -> Bool - +-- | An error indicating that an 'IO' operation failed because +-- one of its arguments already exists. +isAlreadyExistsError :: IOError -> Bool isAlreadyExistsError = isAlreadyExistsErrorType . ioeGetErrorType + +-- | An error indicating that an 'IO' operation failed because +-- one of its arguments does not exist. +isDoesNotExistError :: IOError -> Bool isDoesNotExistError = isDoesNotExistErrorType . ioeGetErrorType + +-- | An error indicating that an 'IO' operation failed because +-- one of its arguments is a single-use resource, which is already +-- being used (for example, opening the same file twice for writing +-- might give this error). +isAlreadyInUseError :: IOError -> Bool isAlreadyInUseError = isAlreadyInUseErrorType . ioeGetErrorType + +-- | An error indicating that an 'IO' operation failed because +-- the device is full. +isFullError :: IOError -> Bool isFullError = isFullErrorType . ioeGetErrorType + +-- | An error indicating that an 'IO' operation failed because +-- the end of file has been reached. +isEOFError :: IOError -> Bool isEOFError = isEOFErrorType . ioeGetErrorType + +-- | An error indicating that an 'IO' operation failed because +-- the operation was not possible. +-- Any computation which returns an 'IO' result may fail with +-- 'isIllegalOperation'. In some cases, an implementation will not be +-- able to distinguish between the possible error causes. In this case +-- it should fail with 'isIllegalOperation'. +isIllegalOperation :: IOError -> Bool isIllegalOperation = isIllegalOperationErrorType . ioeGetErrorType + +-- | An error indicating that an 'IO' operation failed because +-- the user does not have sufficient operating system privilege +-- to perform that operation. +isPermissionError :: IOError -> Bool isPermissionError = isPermissionErrorType . ioeGetErrorType + +-- | A programmer-defined error value constructed using 'userError'. +isUserError :: IOError -> Bool isUserError = isUserErrorType . ioeGetErrorType #endif /* __NHC__ */ @@ -180,47 +230,88 @@ data IOErrorType = AlreadyExists | NoSuchThing | ResourceBusy | PermissionDenied | UserError #endif -alreadyExistsErrorType, doesNotExistErrorType, alreadyInUseErrorType, - fullErrorType, eofErrorType, illegalOperationErrorType, - permissionErrorType, userErrorType :: IOErrorType - +-- | I\/O error where the operation failed because one of its arguments +-- already exists. +alreadyExistsErrorType :: IOErrorType alreadyExistsErrorType = AlreadyExists + +-- | I\/O error where the operation failed because one of its arguments +-- does not exist. +doesNotExistErrorType :: IOErrorType doesNotExistErrorType = NoSuchThing + +-- | I\/O error where the operation failed because one of its arguments +-- is a single-use resource, which is already being used. +alreadyInUseErrorType :: IOErrorType alreadyInUseErrorType = ResourceBusy + +-- | I\/O error where the operation failed because the device is full. +fullErrorType :: IOErrorType fullErrorType = ResourceExhausted + +-- | I\/O error where the operation failed because the end of file has +-- been reached. +eofErrorType :: IOErrorType eofErrorType = EOF + +-- | I\/O error where the operation is not possible. +illegalOperationErrorType :: IOErrorType illegalOperationErrorType = IllegalOperation + +-- | I\/O error where the operation failed because the user does not +-- have sufficient operating system privilege to perform that operation. +permissionErrorType :: IOErrorType permissionErrorType = PermissionDenied + +-- | I\/O error that is programmer-defined. +userErrorType :: IOErrorType userErrorType = UserError -- ----------------------------------------------------------------------------- -- IOErrorType predicates -isAlreadyExistsErrorType, isDoesNotExistErrorType, isAlreadyInUseErrorType, - isFullErrorType, isEOFErrorType, isIllegalOperationErrorType, - isPermissionErrorType, isUserErrorType :: IOErrorType -> Bool - +-- | I\/O error where the operation failed because one of its arguments +-- already exists. +isAlreadyExistsErrorType :: IOErrorType -> Bool isAlreadyExistsErrorType AlreadyExists = True isAlreadyExistsErrorType _ = False +-- | I\/O error where the operation failed because one of its arguments +-- does not exist. +isDoesNotExistErrorType :: IOErrorType -> Bool isDoesNotExistErrorType NoSuchThing = True isDoesNotExistErrorType _ = False +-- | I\/O error where the operation failed because one of its arguments +-- is a single-use resource, which is already being used. +isAlreadyInUseErrorType :: IOErrorType -> Bool isAlreadyInUseErrorType ResourceBusy = True isAlreadyInUseErrorType _ = False +-- | I\/O error where the operation failed because the device is full. +isFullErrorType :: IOErrorType -> Bool isFullErrorType ResourceExhausted = True isFullErrorType _ = False +-- | I\/O error where the operation failed because the end of file has +-- been reached. +isEOFErrorType :: IOErrorType -> Bool isEOFErrorType EOF = True isEOFErrorType _ = False +-- | I\/O error where the operation is not possible. +isIllegalOperationErrorType :: IOErrorType -> Bool isIllegalOperationErrorType IllegalOperation = True isIllegalOperationErrorType _ = False +-- | I\/O error where the operation failed because the user does not +-- have sufficient operating system privilege to perform that operation. +isPermissionErrorType :: IOErrorType -> Bool isPermissionErrorType PermissionDenied = True isPermissionErrorType _ = False +-- | I\/O error that is programmer-defined. +isUserErrorType :: IOErrorType -> Bool isUserErrorType UserError = True isUserErrorType _ = False @@ -253,12 +344,17 @@ ioeSetErrorString ioe str = ioe{ ioe_description = str } ioeSetHandle ioe hdl = ioe{ ioe_handle = Just hdl } ioeSetFileName ioe filename = ioe{ ioe_filename = Just filename } +-- | Catch any 'IOError' that occurs in the computation and throw a +-- modified version. modifyIOError :: (IOError -> IOError) -> IO a -> IO a modifyIOError f io = catch io (\e -> ioError (f e)) -- ----------------------------------------------------------------------------- -- annotating an IOError +-- | Adds a location description and maybe a file path and file handle +-- to an 'IOError'. If any of the file handle or file path is not given +-- the corresponding value in the 'IOError' remains unaltered. annotateIOError :: IOError -> String -> Maybe Handle -- 1.7.10.4