我正在尝试向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
的类型应该是什么?
显然,如果文件存在,我们希望它是一个String
,catch
不应更改其类型,因此无论如何我们都必须生成一个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