1. 導入:なぜ例外処理の整理が必要なのか
プログラミングをしていると、ファイルが見つからない、ネットワークが切れた、独自のエラーが発生したなど、様々な「例外」に直面します。初心者の方が陥りがちなのが、if文やcase文を何重にも重ねて「このエラーならこれ、あれならそれ」と判定する書き方です。これはコードが複雑になるだけでなく、バグの温床にもなります。今回紹介する「catches」関数を使えば、複数の例外ハンドラをリストとして整理でき、宣言的で読みやすいエラー処理を実現できます。
2. 基礎知識:例外ハンドラとは
Haskellにおいて、例外は「型」によって区別されます。例えば、入出力エラー(IOEx)と、ユーザーが独自に定義したエラー(MyEx)は別物として扱われます。
「ハンドラ(Handler)」とは、特定の型のエラーが発生したときに、そのエラーをどう処理するかを記述した「関数を包んだ箱」のようなものです。これらをリストにまとめることで、「この例外が来たらこれを実行、あれが来たらあれを実行」というルールを一覧表のように定義できます。
3. 実装と解決策:catchesの仕組み
`catches`関数は、対象のアクション(処理)と、ハンドラのリストを受け取ります。リストの先頭から順に「発生した例外の型」と「ハンドラが想定している型」を照合し、一致したものが実行されます。これにより、if-then-elseの分岐だらけのコードから解放され、ビジネスロジックとエラー処理を切り離して記述できるようになります。
4. サンプルプログラム
以下のコードは、指定された操作に対して複数の例外を個別にキャッチする例です。そのままコピーしてコンパイル・実行可能です。
import Control.Exception
— 独自のエラー型を定義
data MyCustomError = MyCustomError String deriving Show
instance Exception MyCustomError
main :: IO ()
main = do
— catches関数を使って複数のハンドラを登録
catches (putStrLn “処理を開始します”)
[ Handler (\(e :: IOException) -> putStrLn $ “入出力エラーを検知しました: ” ++ show e)
, Handler (\(e :: MyCustomError) -> putStrLn $ “独自エラーを検知しました: ” ++ show e)
]
— 解説:
— Handler (\(e :: 型) -> …) の形式で、特定の例外型をキャッチする箱を作ります。
— これらをリストに並べることで、発生した例外に応じた柔軟な対応が可能になります。
5. 応用・注意点:現場で役立つアドバイス
実務で使う際の注意点は「ハンドラの順番」です。`catches`はリストの先頭からマッチングを行うため、より具体的な例外(子クラス的なもの)を上に、一般的な例外(Exception全体など)を下に配置するのが定石です。また、すべての例外をキャッチしようとすると、プログラムの終了処理や、Ctrl+Cなどの割り込みまで握りつぶしてしまう可能性があります。例外処理は「適切に回復できるもの」だけを対象にするのが、堅牢なプログラムを作るためのコツです。ぜひ、泥臭い分岐コードをリスト形式に置き換えて、美しいHaskellライフを楽しんでください。

コメント