Самый простой способ - изменить свою функцию, чтобы она больше не была хвостовой рекурсивной. Это то, что я использую, когда я хочу, чтобы хорошие трассировки отображались, когда исключение прерывает программу (в этом случае ocamldebug не нужен, достаточно запустить программу под OCAMLRUNPARAM="b"
; документация ).
Моя личная техника - изменить хвостовой вызов на
let result = <tail call> in result
Ocaml в основном компилирует код в том виде, в котором он написан, и в этом случае это здорово: компилятор этого не встроил, и вы получили красивый обратный след. Конечно, вы можете легко удалить эту деоптимизацию, как только ошибка найдена.
(Это прекрасно работает, когда у вас есть только несколько оконечных вызовов; если у вас их много, вы можете заключить все тело функции в let result = <body> in result
, но я нахожу это немного менее удобным и понятным.)
Если вам нужно, чтобы функция все еще была вызовом taill (например, у вас есть предел размера стека, установленный в ОС, который вы можете исчерпать), вы можете преобразовать стек вызовов для этой функции в структуру данных, превратив
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
, чтобы получить трассировку стека для конкретной функции.