Как я могу получить трассировку стека с хвостовыми вызовами, включенными в Ocaml?

Стек вызовов в ocamldebug является реальным стеком вызовов, поэтому функции, которые сделали хвостовой вызов, не отображаются в нем. Это смущает. Как я могу получить обратную трассировку, которая включает хвостовые вызовы?

2 ответа

Самый простой способ - изменить свою функцию, чтобы она больше не была хвостовой рекурсивной. Это то, что я использую, когда я хочу отображать хорошие следы, когда исключение прерывает программу (в этом случае нет необходимости в 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 переменная, чтобы получить функциональную трассировку стека.

Чтобы увидеть, где находится настоящий хвостовой вызов, я могу многократно набирать "start", чтобы отменить выполнение, и вытолкнуть стек, пока не доберусь до интересующего пункта назначения вызова, а затем выполнить шаг назад. Трудоемко, и должно быть сделано по вызову, но это работает.

Другие вопросы по тегам