Как отлаживать итеративные процедуры?

#debugging #lisp #racket #sicp #dr.racket

#отладка #lisp #ракетка #sicp #dr.racket

Вопрос:

Я использую Dr. Racket и Racket в образовательных целях (изучаю книгу SICP). Доктор Рэкет великолепен, и у него есть потрясающий инструмент под названием «трассировка».

После использования:

 (require trace/racket)
(trace function)
  

Можно увидеть, что происходит в рекурсивной процедуре.

Однако эта функция не работает с итеративными процедурами. Хотел бы я «видеть», что происходит в моем коде во время его выполнения. Хотел бы я видеть изменение значений переменных состояния.

Существует ли альтернативный инструмент или практика для получения такой информации в итеративной процедуре?

Ответ №1:

Трассировка — это не отладка. В DrRacket вы нажимаете кнопку ОТЛАДКИ и щелкаете правой кнопкой мыши по краю интересных частей, например if , которые определяют базовый регистр или регистр по умолчанию в помощнике, и выбираете «Приостановить в этот момент». Затем каждый раз, когда вы нажимаете Go, вы можете видеть связанные аргументы шаг за шагом.

Если вы хотите просто выполнить трассировку, вы можете использовать такой помощник:

 (require racket/trace)
(define (reverse lst)
  (define (aux lst acc)
    (if (null? lst)
        acc
        (aux (cdr lst)
             (cons (car lst) acc))))
  (trace aux) ; tracing the helper
  (aux lst '()))

(reverse '(1 2 3 4))

>(aux '(1 2 3 4) '())
>(aux '(2 3 4) '(1))
>(aux '(3 4) '(2 1))
>(aux '(4) '(3 2 1))
>(aux '() '(4 3 2 1))
<'(4 3 2 1)
;==> (4 3 2 1)
  

Если вы хотите использовать named let , просто замените его на trace-let :

 (define (reverse lst)
  ;; TODO: Put back to let
  (trace-let aux ((lst lst) (acc '()))
    (if (null? lst)
        acc
        (aux (cdr lst)
             (cons (car lst) acc)))))
  

Использование отладчика намного быстрее, чем добавлять и удалять строки в коде для его тестирования.

Комментарии:

1. Точка зрения раздражительного старика: отладчики отняли у меня слишком много времени: никогда не используйте отладчик без конкретного утверждения гипотезы, которую вы тестируете. Во многих случаях (как в полезном примере, предоставленном Сильвестром) вспомогательную функцию можно удалить и сделать отдельной функцией, что упрощает тестирование и отладку. Если ваша программа запутана и ее трудно отлаживать, лучшее, что можно сделать, это упростить ее. <конец разглагольствования>

2. @JohnClements Часто вы используете переменные закрытия, так что подъем является существенной работой. Я согласен, что части должны быть как можно меньше и тестируемыми, как если бы отладчик был недоступен. Lisp обычно заключаются в кавычки для того, чтобы не нуждаться в отладчике, но я редко пишу свой код в других реализациях из-за макрорасширителя и отладчика DrRackets 🙂