ocamldebug のコール スタックは実際のコール スタックであるため、テール コールを行った関数は表示されません。これは紛らわしいです。末尾呼び出しを含むバックトレースを取得するにはどうすればよいですか?
2 に答える
最も簡単な方法は、関数を末尾再帰的でないように変更することです。これは、例外によってプログラムが中止されたときに適切なバックトレースを表示するときに使用するものです (この場合、ocamldebug は必要ありません。プログラムを実行するOCAMLRUNPARAM="b"
だけで十分です。ドキュメント)。
私の個人的なテクニックは、テール コールを次のように変更することです。
let result = <tail call> in result
Ocaml はほとんどの場合、書かれているとおりにコードをコンパイルします。この場合は素晴らしいです。コンパイラはこれをインライン化せず、見栄えの良いバックトレースを取得します。もちろん、バグが見つかったら、この非最適化を簡単に削除できます。(テールコールが数回しかない場合、これは問題なく機能します。テールコールが多い場合は、関数本体全体を でラップできますがlet result = <body> in result
、少し不便で明確ではありません。)
関数を引き続き末尾呼び出しにする必要がある場合 (たとえば、使い果たされる可能性がある 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
変数の値を調べて、関数固有のスタック トレースを取得できます。
実際のテール コールがどこにあるかを確認するには、目的の呼び出し先に到達するまで「start」と繰り返し入力して逆実行し、スタックをポップしてから、バックステップします。手間がかかり、呼び出しごとに実行する必要がありますが、機能します。