ocamldebug中的调用堆栈是真正的调用堆栈,因此进行尾调用的函数不会显示在其中。这令人困惑。如何获得包含尾调用的回溯?
答案 0 :(得分:8)
最简单的方法是更改函数,使其不再是尾递归。这是当我想要在异常中止程序时显示良好的回溯时使用的(在这种情况下不需要ocamldebug,在OCAMLRUNPARAM="b"
下运行程序就足够了; documentation)。
我的个人技巧是将尾调用改为
let result = <tail call> in result
Ocaml主要是在编写代码时编译代码,在这种情况下它很棒:编译器不会内联这个并且你得到一个漂亮的回溯。当然,一旦发现错误,您可以轻松删除此优化。
(当你只有几个尾调用时,这种方法很好;如果你有很多尾调用,你可以将整个函数体包装成let result = <body> in result
,但我觉得它不太方便和清晰。)
如果你需要函数仍然是taill-call(例如,你有一个OS设置的堆栈大小限制,你可能会耗尽),你可以将此函数的调用堆栈重新调整为数据结构,转为
let rec f arg1 arg2 .. argN =
...
f arg1' arg2' .. argN'
到
let rec f stack arg1 arg2 .. argN =
let stack' = (arg1,arg2,..,argN)::stack in
...
f stack' arg1' arg2' .. argN'
然后,您可以在ocamldebug中检查stack
变量的值,以获取特定于函数的堆栈跟踪。
答案 1 :(得分:0)
要查看真正的尾部调用的位置,我可以重复键入“start”来反向执行并弹出堆栈,直到我到达感兴趣的调用目标,然后返回。费力,并且必须在逐个呼叫的基础上完成,但它有效。