3

この関数forkFinallyでは、 に対するハンドラを作成する必要がありますSomeException。必要なのは、未処理の例外を再スローする方法です。e次のサンプル コードは、最後の行があいまいであるためにコンパイルに失敗します。

finallyHandler :: Either SomeException () -> IO ()
finallyHandler z = case z of
  Right () -> cleanUp
  Left someE | Just ThreadKilled <- fromException someE -> cleanUp
             | Just e <- fromException someE -> cleanUp >> throwIO e

もちろん、最初に頭に浮かぶのは、someE代わりに単純にスローすることです。つまり、次のようになります。

             ...
             | otherwise -> cleanUp >> throwIO someE

実際にはコンパイルされますが、SomeExceptionこのハンドラーを渡すと、すべての着信例外がラップされます。これは正しくありません。そして、スタックの下にそのようなハンドラーが複数ある場合はどうなりますか? のようなゴミが表示されますSomeException $ SomeException $ RealException

何か不足していますか?この状況を処理する適切な方法は何ですか?

4

1 に答える 1

2

予期しない動作が見られますか? あなたが実際に嫌なことを引き起こしていないのなら、あなたは何も心配していないと思います. 簡単なテストは、「正しいこと」がすでに行われていることを示しています。つまり、キャッチしてからスローするSomeExceptionと、元の例外を引き続きキャッチできます。ErrorCall根本的な例外として使用する例を次に示します。

> catch (catch (throw (SomeException (ErrorCall "hi")))
               (\(e::SomeException) -> throw e)) 
        (\(ErrorCall e) -> putStrLn e)
hi

これは、 と の定義throwtoExceptiontoException同一性であるためですSomeException

instance Exception SomeException where
    toException se = se
    fromException = Just
于 2013-10-23T18:55:31.310 に答える