2017-08-08 37 views
1

如果一个程序运行并且出现“零除”的消息,那么识别代码中哪里出现这个错误的最好方法是什么?如何用ghc 7.10.3除零产生堆栈轨迹?

+0

你可以限定“最好”吗?一般来说,堆栈跟踪在懒惰的函数式语言中并没有你所期望的那么有意义,所以可能你最好的选择是启用分析。否则,请使用['CallStack'](https://hackage.haskell.org/package/base-4.10.0.0/docs/GHC-Stack.html)。 – user2407038

+0

我想我会解决任何识别错误发生的源代码中的行的方法。当你说启用性能分析时,这是否意味着我可以使用一些额外的参数(哪些?)运行'stack build',然后当我执行程序时,它会伴随更多信息的错误? – kostmo

回答

1

GHC不支持堆栈跟踪,因为没有调用堆栈。您可以做的最好的方法是在基本模块GHC.Stack中使用模拟堆栈跟踪机器。

与GHC 7.8开始,并且因此在7.10.3可用,GHC.Stack暴露

errorWithStackTrace :: String -> a 

作用就像error上正常建立但使用SCC的注释(例如,从--fprof-auto)来构造一个近似堆栈跟踪在异形构建。您将需要重新编译启用分析以支持此功能。如果您正在使用cabal,则可以运行

cabal configure --enable-library-profiling --enable-executable-profiling 

并重建。

从GHC 8.0开始,errorWithStackTrace已弃用,并且由HasCallStack机器提供对呼叫站生成的支持。

GHC.Stack文档现在报价,

函数可以用HasCallStack约束要求其调用点。例如,我们可以定义

errorWithCallStack :: HasCallStack => String -> a 

error变体,将得到其调用点。我们可以通过callStack访问errorWithCallStack内的调用栈。

errorWithCallStack :: HasCallStack => String -> a 
errorWithCallStack msg = error (msg ++ "n" ++ prettyCallStack callStack) 

因此,如果我们调用errorWithCallStack我们将得到一个格式化的调用堆栈与我们的错误消息。

>>> errorWithCallStack "die" 
*** Exception: die 
CallStack (from HasCallStack): 
    errorWithCallStack, called at <interactive>:2:1 in interactive:Ghci1 

(我猜msg ++ "\n"了意思,但"n"是怎样写的。)

虽然你可以用GHC 7.8和获得一些非常有限的堆栈跟踪的支持,我会建议升级如果可能的话,以GHC 8为明显更好的支持。无论哪种方式,它不会是你从其他语言习惯的,但它总比没有好。

+0

在最新的GHC版本中,'error' *是*'errorWithCallStack'。而且这些文档似乎表明你比使用'HasCallStack'获得更好的配置文件的堆栈跟踪。我还没有尝试过配置文件的方式。 – dfeuer

+0

@dfeuer我是否正确理解GHC 8.2.1 w /'-prof'应该产生更好的调用栈?它似乎并不如此:https://gist.github。com/TomMD/7d1fb8dc762fc37bf80b7b7dd447e29a –

+0

即使启用性能分析(通过'stack build --profile'),我只看到错误消息“除以零”,没有额外的上下文。假设有一个代码库,其中除法操作('/'或'\'div \'')出现在几十个呼叫站点。如果在运行时遇到错误消息“被零除”,并且任何这些调用站点似乎都可能成为错误源,那么如何调试呢?必须用一些带注释的版本来替换除法操作的每个实例(充其量,缩小二进制搜索中的违规呼叫站点)? – kostmo