'readFile'的异常处理

G-J*_*G-J 4 error-handling file-io haskell handler

我正在尝试为函数添加一个简单的处理程序readFile:

readHandler :: IOError -> IO ()  
readHandler e  
    | isDoesNotExistError e = putStrLn "The file does not exist"
    | otherwise = putStrLn "Something went wrong"  

main = do
    // stop executing if there is no file   
    contents <- (readFile "path.xml") `catch` readHandler
    // generates [(x,y),(x,y)]
    coordinates = parseXML contents
    // I want to do something with the coordinates
    nextFunction coordinates
Run Code Online (Sandbox Code Playgroud)

当我尝试编译这个时,我收到错误:

Couldn't match type `()' with `[Char]'
Expected type: IOError -> IO String
  Actual type: IOError -> IO ()
In the second argument of `catch', namely `readHandler'
In a stmt of a 'do' block:
  contents <- (readFile "path") `catch` readHandler
In the expression:
  do { contents <- (readFile "path") `catch` readHandler;
       putStrLn contents }
Run Code Online (Sandbox Code Playgroud)

因此,readHandler :: IOError -> IO ()应该是readHandler :: IOError -> IO String.

但这种方式我无法打印错误信息.

我该如何解决这个问题?

Dan*_*zer 6

应该是什么类型的catch (readFile "path") readHandler

显然,如果文件存在,我们希望它是一个String,catch不应该改变它的类型,所以无论如何我们必须产生一个String无论如何.因为如果抛出异常,readHandler运行它也必须产生一个字符串.

这种方式catch就像一个非常复杂的if表达式:)但是,它不太理想,因为我们不想继续运行我们的函数与一些String不是来自文件的随机.

相反,我们可以做类似的事情

 main = handle readHandler $ do
    ...
Run Code Online (Sandbox Code Playgroud)

从现在开始,我们只需要制作一个IO (),琐碎的.

如果由于某种原因这不能漂浮你的船,另一个理智的选择是将这个令人不快的例外转变为更愉快 Either

 main = do
   strOrExc <- try $ readFile "foo"
   case strOrExc of
     Left except -> print except
     Right contents -> putStrLn contents
Run Code Online (Sandbox Code Playgroud)

当然,你可以Exception e => Either e a用任何方式处理这个带给你快乐的事情.

当然还有最后的选择,让整个程序在当时和那里戛然而止.我们可以通过改变来做到这一点readHandler

import System.Exit

readHandler :: IOError -> IO a
readHandler = putStrLn "Buckle your seatbelts" >> exitFailure
Run Code Online (Sandbox Code Playgroud)