我正在尝试向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

当我尝试对此进行编译时,出现错误:
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 }

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

但是这样我不能打印错误信息。

我应该如何解决这个问题?

最佳答案

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

显然,如果文件存在,我们希望它是一个Stringcatch不应更改其类型,因此无论如何我们都必须生成一个String。由于如果引发异常,则运行readHandler,因此它还必须产生一个字符串。

这样,catch就像一个非常复杂的if表达式:)但是,这并不理想,因为我们不想继续使用不是来自文件的随机String来运行我们的函数。

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

 main = handle readHandler $ do
    ...

从现在开始,我们只需要生成IO ()即可。

如果由于某种原因而不能使您的船漂浮起来,那么另一个明智的选择是将令人烦恼的异常转换为更舒适的Either
 main = do
   strOrExc <- try $ readFile "foo"
   case strOrExc of
     Left except -> print except
     Right contents -> putStrLn contents

当然,您可以通过任何可以带来幸福的方式来处理这个Exception e => Either e a

当然,还有最后的选择,那就是使整个程序随即停止运行。我们可以通过更改readHandler来做到这一点
import System.Exit

readHandler :: IOError -> IO a
readHandler = putStrLn "Buckle your seatbelts" >> exitFailure

08-07 22:20