import IO

Section 7.3

第 7.3 节

To experiment with I/O errors, we need to get a bit creative. Generating an error is generally OS specific so instead we will use errors that are directly under user control. The function

要试验 I/O 错误,我们需要一点创造力。产生错误通常依赖于具体操作系统,

所以我们将改由用户直接掌控来制造错误。函数

userError :: String -> IOError

generates an error value and the function

生成一个错误值;而函数

ioeGetErrorString :: IOError -> String

gets the string out of an error.

从错误中取出字符串。

This version of getChar that raises an error when an @ or ? is entered:

下面是 getChar 的一个版本,当输入 @ 或 ? 时抛出错误:

getCharE           :: IO Char
getCharE           =  do c <- getChar
                         case c of
                           '@' -> ioError (userError "@")
                           '?' -> ioError (userError "?")
                           _   -> return c

Using this extended getChar we can build getChar' to catch only @ There is currently a bug in Hugs - if this gets fixed change the definition is isAtError.

利用这个扩展的 getChar,我们可以构造只捕获 @ 的 getChar'。

Hugs 目前有个 bug——如果它被修复了,请更改 isAtError 的定义。

isAtError :: IOError -> Bool
isAtError e = ioeGetErrorString e == "User error: @"  -- for bug in hugs
-- isAtError e = ioeGetErrorString e == "@"   -- Should be this
getChar'                :: IO Char
getChar'                =  getCharE `catch` atHandler where
    atHandler e = if isAtError e then return '\n' else ioError e
getLine'        :: IO String
getLine'        = catch getLine'' (\err -> return ("Error: " ++ show err))
    where
                   getLine'' = do c <- getChar'
                                  if c == '\n' then return ""
                                               else do l <- getLine'
                                                       return (c:l)

Observe the behavior when you enter @ or ?

观察你输入 @ 或 ? 时的行为。

e1 = getCharE

Now try lines with @ and ? in them.

现在试试包含 @ 和 ? 的行。

e2 = do l <- getLine'
        putStrLn l

Section 7.4

第 7.4 节

You will have to set up some files to play with if you want to try this one.

如果想试这个例子,你得先准备一些文件来操作。

e3 = do fromHandle <- getAndOpenFile "Copy from: " ReadMode
        toHandle   <- getAndOpenFile "Copy to: " WriteMode
        contents   <- hGetContents fromHandle
        hPutStr toHandle contents
        hClose toHandle
        putStr "Done."
getAndOpenFile          :: String -> IOMode -> IO Handle
getAndOpenFile prompt mode =
   do putStr prompt
      name <- getLine
      catch (openFile name mode)
            (\_ -> do putStrLn ("Cannot open "++ name ++ "\n")
                      getAndOpenFile prompt mode)