4

ocamldebug中的調用堆棧是真正的調用堆棧,因此已經做出尾部調用的函數不會顯示在其中。這很混亂。我如何獲得包含尾部呼叫的回溯?如何獲得包含在Ocaml中的尾部調用的堆棧跟蹤?

+0

有趣的問題。我猜測這將涉及禁用尾部優化,因爲程序很難顯示已被完全覆蓋的堆棧幀。如果有人發現如何做到這一點,您可能還需要提高堆棧限制(在Bash中爲'ulimit -s')。 –

回答

7

最簡單的方法是改變你的函數,使它不再是尾遞歸。這就是我使用的情況,當我想要在執行異常終止程序時顯示好回溯(在這種情況下不需要ocamldebug,運行程序OCAMLRUNPARAM="b"就足夠了; documentation)。

我個人的方法是改變尾調用到

let result = <tail call> in result 

ocaml的大多是編譯代碼,因爲它是寫的,在這種情況下,它是偉大的:編譯器不內聯這個,你會得到一個不錯的俯瞰回溯。當然,一旦發現錯誤,您可以輕鬆地刪除該優化。當你只有幾個尾巴呼叫時,這個工作正常;如果你有很多尾巴,你可以把整個功能體包裝成let result = <body> in result,但是我覺得它不太方便和清晰。)

If你需要的功能仍然是taill呼叫(例如,你有一個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變量的值,以獲取函數特定的堆棧跟蹤。

+0

不幸的是,我實際上在探索一個陌生的代碼庫(Coq),所以我不能立即知道在回溯中可以看到的函數的哪些調用者是真正的調用者。 –

0

要查看真實尾部呼叫的位置,我可以重複鍵入「開始」以反轉執行並彈出堆棧,直到到達感興趣的呼叫目標,然後回退。費力,而且必須在逐個呼叫的基礎上完成,但它很有效。