第25回 Haskell流の例外処理を学ぶ を参考に例外を捕捉してみます。
haskellでの例外処理は
catch (例外が発生する可能性のある関数) (例外が起きた場合に実行する関数)
という書き方をします。
「ファイルを開いて表示する」という処理を実行しようとしたとき、ファイル名が間違っていたり、ファイルがなかったりするとエラーが発生してプログラムが停止してしまいますが、その例外を補足してみます。
module Exception where import Control.Exception import Prelude hiding (catch) fRead :: FilePath -> IO () fRead fileName = catch (showFile fileName) (showError fileName) showFile :: FilePath -> IO () showFile file = putStr =<< readFile file showError :: String -> SomeException -> IO () showError file e = do return (e::SomeException) putStrLn $ "File:" ++ file ++ " does not exist (No such file or directory)"
catch 関数は第一引数にIO型の関数、第二引数にExceptionクラスのインスタンスを引数にとり、IO型を返します。関数が実行するのはここまでで、第一引数のIO型か第二引数のIO型が返されるのでHaskellの実行環境がそのアクションを関数とは離れた外部で実行する、というイメージでしょうか。
catch :: (Exception e) => IO a -> (e -> IO a) -> IO a
二番目の引数 (showError fileName) には Exceptionクラスのインスタンスが渡されています。この型が「不特定多数の例外を表現する型」なので (e::SomeException) で型を強制しています。(第25回 Haskell流の例外処理を学ぶ)
通常の言語ですと return (e::SomeException) で showError 関数を抜けてしまいそうですが・・・そうではないようで、IO型にくるんでいるようです。
ファイルがあれば表示
ghci> fRead "exception.hs" module Exception where (snip) putStrLn $ "File:" ++ file ++ " does not exist (No such file or directory)"
ファイルがなければエラー表示
ghci> fRead "exception.hss" File:exception.hss does not exist (No such file or directory)
もっと上のレイヤから呼んでみる。
ghci> (\f->catch (fRead f) (showError f)) "exception.hs" module Exception where import Control.Exception import Prelude hiding (catch) (snip) ghci> (\f->catch (fRead f) (showError f)) "exception.hss" File:exception.hss does not exist (No such file or directory)