我正在构建一个 Haskell 应用程序并试图弄清楚我将如何构建错误处理机制。在实际应用程序中,我正在使用 Mongo 进行大量工作。但是,为此,我将通过对文件进行基本 IO 操作来简化操作。
因此,对于这个测试应用程序,我想读入一个文件并验证它是否包含正确的斐波那契数列,每个值用空格分隔:
1 1 2 3 5 8 13 21
现在,在读取文件时,实际上可能有很多事情是错误的,我将在 Haskell 对单词的用法中调用所有这些异常。
data FibException = FileUnreadable IOError
| FormatError String String
| InvalidValue Integer
| Unknown String
instance Error FibException where
noMsg = Unknown "No error message"
strMsg = Unknown
编写一个纯函数来验证序列并在序列无效的情况下抛出错误很容易(尽管我可能会做得更好):
verifySequence :: String -> (Integer, Integer) -> Either FibException ()
verifySequence "" (prev1, prev2) = return ()
verifySequence s (prev1, prev2) =
let readInt = reads :: ReadS Integer
res = readInt s in
case res of
[] -> throwError $ FormatError s
(val, rest):[] -> case (prev1, prev2, val) of
(0, 0, 1) -> verifySequence rest (0, 1)
(p1, p2, val') -> (if p1 + p2 /= val'
then throwError $ InvalidValue val'
else verifySequence rest (p2, val))
_ -> throwError $ InvalidValue val
之后,我想要读取文件并验证序列的函数:
type FibIOMonad = ErrorT FibException IO
verifyFibFile :: FilePath -> FibIOMonad ()
verifyFibFile path = do
sequenceStr <- liftIO $ readFile path
case (verifySequence sequenceStr (0, 0)) of
Right res -> return res
Left err -> throwError err
如果文件格式无效(返回Left (FormatError "something")
)或文件的编号乱序(Left (InvalidValue 15)
),则此函数完全符合我的要求。但如果指定的文件不存在,则会引发错误。
如何捕获 readFile 可能产生的 IO 错误,以便将它们转换为 FileUnreadable 错误?
作为一个附带问题,这甚至是最好的方法吗?我看到了调用者verifyFibFile
不必设置两种不同的异常处理机制而可以只捕获一种异常类型的优点。