Ничто не мешает вам использовать точки останова в лениво оцененной функциональной программе. Разница с нетерпеливой оценкой составляет , когда программа остановится на точке останова и как будет выглядеть трассировка. Программа остановится, когда выражение, на котором установлена точка останова, фактически сокращается (очевидно).
Вместо того, чтобы использовать трассировку стека, вы получаете сокращения, которые привели к сокращению выражения с точкой останова на нем.
Маленький глупый пример. У вас есть эта программа на Haskell.
add_two x = 2 + x
times_two x = 2 * x
foo = times_two (add_two 42)
И вы ставите точку останова в первой строке (add_two
), а затем оцениваете foo
. Когда программа останавливается на точке останова, на нетерпеливом языке вы ожидаете иметь трассировку, такую как
add_two
foo
и times_two
даже не начали оцениваться, но в отладчике GHCi вы получаете
-1 : foo (debug.hs:5:17-26)
-2 : times_two (debug.hs:3:14-18)
-3 : times_two (debug.hs:3:0-18)
-4 : foo (debug.hs:5:6-27)
<end of history>
- это список сокращений, которые привели к сокращению выражения, на которое вы ставите точку останова. Обратите внимание, что это выглядит как times_two
«вызываемый» foo
, хотя это явно не так. Из этого вы можете видеть, что оценка 2 * x
в times_two
(-2) действительно вынудила оценку (add_two 42)
(-1) из строки foo
. Оттуда вы можете выполнить шаг, как в императивном отладчике (выполнить следующее сокращение).
Еще одно отличие от отладки в нетерпеливом языке состоит в том, что переменные еще не оценены. Например, на шаге 2 в приведенной выше трассировке и проверке x
вы обнаружите, что это все еще неоцененный отрывок (указан в скобках в GHCi).
Более подробную информацию и примеры (как пройти по трассировке, проверить значения, ...) см. В разделе отладчика GHCi в руководстве по GHC. Есть также Leksah IDE , который я еще не использовал, так как я являюсь пользователем VIM и терминалом, но в соответствии с инструкцией у него есть графический интерфейс для отладчика GHCi.
Вы также запросили печатные заявления. Только с чистыми функциями это сделать не так просто, так как оператор print должен находиться внутри монады ввода-вывода. Итак, у вас есть чистая функция
foo :: Int -> Int
и при желании добавить оператор трассировки, печать будет возвращать действие в монаде IO, и вам придется настраивать сигнатуру функции, в которую вы хотите поместить этот оператор трассировки, и сигнатуры функций, которые позвони, ...
Это не очень хорошая идея. Итак, вам нужен какой-то способ нарушить чистоту, чтобы получить трассировочные выражения. В Haskell это можно сделать с помощью unsafePerformIO
. Модуль Debug.Trace
уже имеет функцию
trace :: String -> a -> a
, который выводит строку и возвращает второй параметр. Было бы невозможно написать как чистую функцию (ну, если вы действительно хотите вывести строку, то есть). Он использует unsafePerformIO
под капотом. Вы можете поместить это в чистую функцию для вывода отпечатка трассы.
Придется ли вам программировать монаду для каждого раздела кода, который вы хотите протестировать?
Я бы предложил скорее наоборот, сделать как можно больше функций чистыми (я предполагаю, что здесь вы имеете в виду монаду ввода-вывода для печати, монады не обязательно являются нечистыми). Ленивая оценка позволяет очень аккуратно отделить код ввода-вывода от обработки кода.
Является ли императивная техника отладки хорошей идеей или нет, зависит от ситуации (как обычно). Я считаю тестирование с помощью QuickCheck / SmallCheck гораздо более полезным, чем модульное тестирование на императивных языках, поэтому сначала я бы пошел по этому пути, чтобы избежать как можно больше отладки. Свойства QuickCheck на самом деле дают хорошие лаконичные спецификации функций (для меня большое количество тестового кода на императивных языках выглядит как очередной кусочек кода).
Один из способов избежать отладки - это разложить функцию на множество меньших подфункций и протестировать как можно больше из них. Это может быть немного необычно, если исходить из императивного программирования, но это хорошая привычка, независимо от того, какой язык вы используете.
Опять же, отладка! = Тестирование, и если где-то что-то пойдет не так, точки останова и трассировки могут вам помочь.