7

例外がキャッチされないときはいつでも巨大なスタック トレースを出力する JVM 言語から来ているconnect: does not exist (Connection refused)ので、プログラムの出力に次のようなものが表示され、それ以外に何も表示されずに閉じられると、イライラします。一部の例外が発生し、キャッチされなかったことを理解しています。オフライン サーバーに接続しようとしたため、例外が発生することさえ予想していました。したがって、必要なのはこの例外を処理する方法だけですが、理解できないのは、それを行うためにその例外のタイプを見つける方法です。

今日まで私が通常行っていたのは、特定のメッセージをグーグルで検索し、すべてのメーリングリストのアーカイブまたはソースファイルを調べて情報を検索することでしたが、それは正しいアプローチではありません. だから、私の質問はタイトルのとおりです:

キャッチされていない例外の種類を追跡する方法は?

4

4 に答える 4

8

typeOf例外のタイプを出力するために使用できます。

import Data.Typeable
import Control.Exception
import System.IO.Error

blackbox1 :: IO ()
blackbox1 = throw $ mkIOError doesNotExistErrorType "blackbox1" Nothing (Just "evil")

blackbox2 :: IO ()
blackbox2 = throw DivideByZero

traceExceptionName :: IO () -> IO ()
traceExceptionName act = act `catch` \(SomeException e) -> do
  let rep = typeOf e
      tyCon = typeRepTyCon rep
  putStrLn $ "## Exception: Type " ++ show rep ++ " from module " ++ tyConModule tyCon ++ " from package " ++ tyConPackage tyCon
--  throw e -- Rethrow exception.

main :: IO ()
main = do
  traceExceptionName blackbox1
  traceExceptionName blackbox2

出力例

$ runhaskell ./main.hs            
## Exception: Type IOException from module GHC.IO.Exception from package base
## Exception: Type ArithException from module GHC.Exception from package base
于 2013-10-24T13:55:01.303 に答える
4

型だけが必要な場合は、typeOfを使用してみませんか? すべての例外は のインスタンスでなければなりませんTypeable

于 2013-10-24T13:47:11.977 に答える
4

これは本当に Haskell の最悪の部分の 1 つです。スタック トレースを取得するのは非常に困難です。

最も直接的な方法は、プロファイリング用にプログラムをコンパイルしてから、RTS オプションを指定して呼び出すことです。

myprog +RTS -xc -RTS

これはスタック トレースをダンプしますが、少しバグがあり、うまく機能しない可能性があると聞いています。これはドキュメントの例です

*** Exception raised (reporting due to +RTS -xc), stack trace:
  GHC.List.CAF
  --> evaluated by: Main.polynomial.table_search,
  called from Main.polynomial.theta_index,
  called from Main.polynomial,
  called from Main.zonal_pressure,
  called from Main.make_pressure.p,
  called from Main.make_pressure,
  called from Main.compute_initial_state.p,
  called from Main.compute_initial_state,
  called from Main.CAF

-xcただし、十分な追加情報が提供されなかった場合は、特定のエラー文字列のソースを grep するところまで行っています。

特定のライブラリを介してキャッチできない例外が発生し、それをより純粋な方法で処理したい場合は、spoonパッケージ内の関数を使用してそれを純粋なMaybe結果に変換することをお勧めします。そこから、独自の例外を介して再発生させることができます。これにより、エラーの処理も容易になる場合があります。

于 2013-10-24T11:48:26.017 に答える
1

J.アブラハムソンの答えが好きですが、それが失敗した場合、または代替が必要な場合...「すべての」例外をキャッチするハンドラーを一時的に作成し、例外の名前を出力します。それができたら、処理できる例外のみを処理するように例外ハンドラーを変更します。

ただし、 「すべての例外をキャッチする」に関する警告を読んでください


編集:ここにいくつかのサンプルコードがあります:

catch XXXXXXX
  (\e -> do
     let err = show (e :: SomeException)
     hPutStr stderr ("Warning: " ++ err)
     return ())
于 2013-10-24T11:54:07.077 に答える