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 中最糟糕的部分之一——很难从中获取堆栈跟踪。

最直接的方法是编译程序进行分析,然后使用 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结果。从那里你可以通过你自己的例外重新提出它。这也可能使错误更容易处理。

于 2013-10-24T11:48:26.017 回答
1

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

但请阅读有关“捕获所有异常”的警告


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

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