[解決済み] Haskellの例外処理
質問
3つのHaskell関数の使い方を理解する手助けが欲しいです。
-
を試す (
Control.Exception.try :: Exception e => IO a -> IO (Either e a)
) -
キャッチ (
Control.Exception.catch :: Exception e => IO a -> (e -> IO a) -> IO a
) -
ハンドル (
Control.Exception.handle :: Exception e => (e -> IO a) -> IO a -> IO a
)
いくつか知りたいことがあります。
- どの機能をいつ使えばいいのか?
- この関数はどのように使うのか、簡単な例を挙げて説明します。
- catchとhandleの違いは何ですか?順番が違うだけで、ほぼ同じシグネチャを持っています。
私の試行錯誤を書き留めますので、よろしくお願いします。
試す
みたいな例があります。
x = 5 `div` 0
test = try (print x) :: IO (Either SomeException ())
2つ質問があります。
-
カスタムエラー出力を設定するにはどうすればよいですか?
-
すべてのエラーをSomeExceptionに設定するために、私は何をすることができ、私はそれを書く必要がありません。
:: IO (Either SomeException())
catch/try
カスタムエラー出力の短い例を示してもらえますか?
どのように解決するのですか?
どのような場合に、どの機能を使用するのですか?
Control.Exceptionのドキュメントにある推奨事項は以下の通りです。
-
例外が発生した際に、何らかの後始末をしたい場合は
finally
,bracket
またはonException
. -
例外の後に回復して他のことをするために、最適な選択は
try
ファミリーを使用することです。 -
... 非同期例外から回復する場合を除き、その場合は
catch
またはcatchJust
.
try :: Exception e => IO a -> IO (どちらかのe a)
try
を取る。
IO
アクションを実行し
Either
. 計算が成功した場合、その結果は
Right
コンストラクタに包まれて与えられる。(間違ったことではなく、正しいことと考えてください)。もしアクションが例外を投げたら
が指定されたタイプの
で返されます。
Left
コンストラクタで返されます。もし例外が
ではなく
でない場合、例外はスタック上に伝搬し続けます。指定する
SomeException
を型として指定すると、すべての例外をキャッチすることになります。
純粋な計算からの例外を捕捉したい場合は、その例外を捕捉するために
evaluate
の中で強制的に評価させる必要があります。
try
.
main = do
result <- try (evaluate (5 `div` 0)) :: IO (Either SomeException Int)
case result of
Left ex -> putStrLn $ "Caught exception: " ++ show ex
Right val -> putStrLn $ "The answer was: " ++ show val
catch :: Exception e => IO a -> (e -> IO a) -> IO a
catch
は
try
. これはまず、指定された
IO
アクションを実行しようとしますが、もし例外が発生した場合は、代替の答えを得るためにハンドラに例外が渡されます。
main = catch (print $ 5 `div` 0) handler
where
handler :: SomeException -> IO ()
handler ex = putStrLn $ "Caught exception: " ++ show ex
しかし
には1つ重要な違いがあります。を使用する場合
catch
を使う場合、ハンドラは非同期例外 (すなわち、他のスレッドから
throwTo
). 非同期例外を発生させようとすると、ハンドラの実行が終了するまでブロックされます。
別の
catch
があるので、前奏曲で
import Prelude hiding (catch)
.
handle :: 例外e => (e -> IO a) -> IO a -> IO a
handle
は、単純に
catch
であり、引数の順番が逆になっています。どちらを使うかは、コードを読みやすくするか、部分適用を使いたい場合にどちらが合うかによります。それ以外は同じです。
tryJust、catchJust、handleJust
以下のことに注意してください。
try
,
catch
と
handle
がキャッチするのは
すべて
の例外を捕捉します。
tryJust
とその仲間では、特に処理したい例外をフィルタリングするセレクタ関数を指定することができます。例えば、全ての算術演算エラーは
ArithException
. をキャッチしたいだけなら
DivideByZero
をキャッチしたいだけなら、できます。
main = do
result <- tryJust selectDivByZero (evaluate $ 5 `div` 0)
case result of
Left what -> putStrLn $ "Division by " ++ what
Right val -> putStrLn $ "The answer was: " ++ show val
where
selectDivByZero :: ArithException -> Maybe String
selectDivByZero DivideByZero = Just "zero"
selectDivByZero _ = Nothing
純度に関する注意事項
この種の例外処理は、不純物のないコード (すなわち
IO
モナド) でのみ発生することに注意してください。純粋なコードでエラーを処理する必要がある場合は、以下のような方法で値を返すことを検討する必要があります。
Maybe
または
Either
のような代数的なデータ型に置き換えてください。この方がより明示的で、どこで何が起こりうるかが常にわかるので、しばしば好ましい。のようなモナドは
Control.Monad.Error
のようなモナドは、この種のエラー処理をより簡単にします。
こちらもご覧ください。
関連
-
[解決済み] Haskell Preludeの'const'は何のためにあるのか?
-
[解決済み] Pythonの関数が例外を投げるかどうかをテストするにはどうすればよいですか?
-
[解決済み] Rubyで「例外 => e」を救済するのはなぜ悪いスタイルなのですか?
-
[解決済み] Node.jsの例外処理のベストプラクティス
-
[解決済み] Pythonのwith文の使用中に例外をキャッチする
-
[解決済み】C++の例外を投げる方法
-
[解決済み】再試行キャッチはどのように実装するのですか?
-
[解決済み】Haskellの入門編
-
[解決済み] Spring Boot RESTサービスの例外処理
-
[解決済み] Haskellのドット演算子:もっと説明が欲しい
最新
-
nginxです。[emerg] 0.0.0.0:80 への bind() に失敗しました (98: アドレスは既に使用中です)
-
htmlページでギリシャ文字を使うには
-
ピュアhtml+cssでの要素読み込み効果
-
純粋なhtml + cssで五輪を実現するサンプルコード
-
ナビゲーションバー・ドロップダウンメニューのHTML+CSSサンプルコード
-
タイピング効果を実現するピュアhtml+css
-
htmlの選択ボックスのプレースホルダー作成に関する質問
-
html css3 伸縮しない 画像表示効果
-
トップナビゲーションバーメニュー作成用HTML+CSS
-
html+css 実装 サイバーパンク風ボタン
おすすめ
-
[解決済み] エラー haskell: スコープ内にありません。どういう意味ですか?
-
[解決済み] Haskell - Ord aの型は何を意味するのでしょうか?
-
[解決済み] 機能における非網羅的なパターン【重複あり
-
[解決済み] haskellにおけるdrop関数 - リスト内包を用いた実装
-
[解決済み] Haskellは実世界で何に使われているのか?[クローズド]
-
[解決済み] 制約条件付き特殊化
-
[解決済み] Haskellのマルチコアプログラミングはどうなっているのか?
-
[解決済み] 無限リストでのfoldlとfoldrの動作
-
[解決済み] Haskellのストリクトネスポイントは何ですか?
-
[解決済み] Lazy I/Oの何がそんなに悪いのか?