如何追踪未捕获的异常类型?

时间:2013-10-24 11:39:54

标签: exception haskell

来自JVM语言,每当异常未被捕获时输出庞大的堆栈跟踪,当我看到类似connect: does not exist (Connection refused)之类的内容并且程序输出中没有其他内容然后关闭时,我会感到沮丧。我知道有些例外被提出而没有被抓住。我甚至预计会发生异常,因为我试图连接到脱机服务器。所以我只需要一种方法来处理这个异常,但我不明白的是我应该如何找出那种异常的类型。

我今天通常做的只是谷歌搜索特定的消息,并通过所有邮件列表存档或源文件搜索信息,但这不是正确的方法。所以,我的问题如标题所示:

如何追踪未捕获的异常类型?

4 个答案:

答案 0 :(得分:7)

您可以使用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

答案 1 :(得分:4)

这真的是Haskell最糟糕的部分之一 - 很难从中获取堆栈跟踪。

最直接的方法是编译程序以进行性能分析,然后使用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没有提供足够的额外信息时,我已经过了特别错误字符串的来源。

如果你有一个无法捕获的异常通过一个特定的库上升并且你想以更纯粹的方式处理它,你可能想使用spoon包中的函数将它转换为一个纯Maybe的结果。从那里你可以通过自己的例外重新提出它。这可能会使错误更容易处理。

答案 2 :(得分:4)

如果您需要的只是类型,为什么不使用typeOf?所有例外都必须是Typeable的实例。

答案 3 :(得分:1)

我喜欢J. Abrahamson的回答,但是如果失败或者你想要一个替代方案......我暂时编写一个捕获“所有”异常的处理程序,只打印出异常的名称。有了这个,我修改了异常处理程序,只处理我能处理的异常。

但请阅读warning about "Catching all exceptions"


编辑:这是一些示例代码:

catch XXXXXXX
  (\e -> do
     let err = show (e :: SomeException)
     hPutStr stderr ("Warning: " ++ err)
     return ())