私は 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
の呼び出し元が2 つの異なる例外処理メカニズムをセットアップする必要がなく、代わりに 1 つの例外タイプだけをキャッチできるという利点があることがわかりました。