如何获取有关Haskell错误发生位置的更多信息?例如,昨天我正在研究一个Haskell程序,它解析输入文件,转换数据然后打印出报告信息。
有一次,我跑了“主”并回来了
*** Prelude.read: parse error
没有其他信息。幸运的是,我知道我只是在一个地方打电话阅读并且能够修复它,但是对于未来:
谢谢!
修改使用GHC。
答案 0 :(得分:8)
如果你可以在ghci中运行代码,那么调试器可以做你想做的一切。这是一个引发异常的程序
foo s i
| i == 57 = read s
| otherwise = i
main = mapM_ (print . foo "") [1..100]
现在将其加载到ghci并使用调试器,如下所示: http://www.haskell.org/ghc/docs/latest/html/users_guide/ghci-debugger.html#ghci-debugger-exceptions
> ghci test.hs
*Main> :set -fbreak-on-error
*Main> :trace main
1
2
... snipped 3 through 55 ...
56
Stopped at <exception thrown>
_exception :: e = _
[<exception thrown>] *Main> :back
Logged breakpoint at test.hs:2:15-20
_result :: a
s :: String
[-1: test.hs:2:15-20] *Main> :list
1 foo s i
2 | i == 57 = **read s**
3 | otherwise = i
[-1: test.hs:2:15-20] *Main> s
""
[-1: test.hs:2:15-20] *Main>
它允许您在评估历史记录中四处走动,突出显示引发异常的实际表达式(粗体而非在终端上加星标),并允许您检查局部变量。
另一种选择是使用分析和一些标记重新编译以标记适当的成本中心,并使用-xc分析选项运行,该选项在未捕获的异常上打印成本中心堆栈 http://www.haskell.org/ghc/docs/latest/html/users_guide/prof-time-options.html
> ghc -prof -auto-all test.hs
> ./test +RTS -cs
1
2
... snipped 3 through 55 ...
56
*** Exception (reporting due to +RTS -xc): (THUNK_2_0), stack trace:
Main.foo,
called from Main.main,
called from Main.CAF
--> evaluated by: Main.main,
called from Main.CAF
test: Prelude.read: no parse
在调试器页面上稍早描述了这有点困难的原因 http://www.haskell.org/ghc/docs/latest/html/users_guide/ghci-debugger.html#tracing 基本上,高效的Haskell执行不会使用类似于普通调用堆栈的任何东西,因此要获得有关异常的那种信息,您必须在某种特殊模式(调试或分析)中运行,这样可以保留这种信息。
答案 1 :(得分:6)
您可以通过导入Debug.Trace
并更改来获取导致解析错误的字符串
你的电话
import Debug.Trace (trace) --change myRead s = read s --to myRead s = trace s (read s) --or myRead s = trace (take 100 s) (read s)
答案 2 :(得分:3)
通常,您可以通过这样的方式处理错误,即有足够的上下文来调试原因。
Haskell的惰性使堆栈跟踪难以实现,因为在错误发生时调用堆栈可能不再存在。
一种简单的错误处理方法是使用Either类型,它允许您在事情正确时返回值,或者在出现错误时返回某些上下文(错误消息,输入字符串......)。
最后,在你的特定情况下read
抛出一个异常,所以你必须捕获它然后处理调用代码中的错误(看看Control.Exception
包)。
答案 3 :(得分:2)
您没有告诉我们您使用的是哪种编译器。如果您使用GHC,那么您应该查看GHCi Debugger。
Haskell中的堆栈跟踪并不简单,因为它的懒惰。尽管如此,上述调试器提供了一些工具(参见上面URL中的2.5.5。跟踪和历史记录)。
答案 4 :(得分:1)
您可以考虑使用另一个StackOverflow用户"Practical Haskell: shell scripting with error handling and privilege separation"在dons中使用monadic read
:
第一步是将
read
替换为提升为通用错误monadMonadError
的版本:readM :: (MonadError String m, Read a) => String -> m a readM s | [x] <- parse = return x | otherwise = throwError $ "Failed parse: " ++ show s where parse = [x | (x,t) <- reads s]