Использование «отладки printf»
Вы можете позволить Emacs помочь вам понять, изменив определение функции:
(defun triangle-using-cond (number)
(message (format "called with %d" number))
(cond ((<= number 0) 0)
((= number 1) 1)
((> number 1)
(+ number (triangle-using-cond (1- number))))))
Просто добавьте (message ...)
куда-нибудь, чтобы в *Messages*
буфер был напечатан след .
Используя Edebug
Поместите точку в любое место внутри определения функции и нажмите C-u C-M-x
«инструмент». Затем оцените функцию, например, поставив точку после (triangle-using-cond 3)
и нажав C-x C-e
.
Теперь вы находитесь в режиме Edebug. Нажмите пробел, чтобы пройти через функцию. Промежуточные значения каждого выражения отображаются в области эха. Для выхода из режима Edebug просто нажмите q
. Чтобы удалить инструментарий, поместите точку в любом месте определения и нажмите, C-M-x
чтобы переоценить определение.
Использование стандартного отладчика Emacs
M-x debug-on-entry triangle-using-cond
затем, когда triangle-using-cond
вызывается, вы помещаетесь в отладчик Emacs (буфер *Backtrace*
).
Пройдите оценку, используя d
(или c
пропустите любые неинтересные оценки).
Чтобы увидеть промежуточное состояние (значения переменных и т. Д.), Вы можете использовать в e
любое время. Вам будет предложено ввести sexp для оценки, и результат оценки будет напечатан.
Пока вы используете отладчик, держите копию исходного кода видимой в другом фрейме, чтобы вы могли следить за тем, что происходит.
Вы также можете вставить явные вызовы для входа в отладчик (более или менее точек останова) в произвольных местах исходного кода. Вы вставляете (debug)
или (debug nil SOME-SEXP-TO-EVALUATE)
. В последнем случае при вводе отладчика SOME-SEXP-TO-EVALUATE
выполняется оценка и выводится результат. (Помните, что вы можете вставить такой код в исходный код и использовать его C-M-x
для оценки, а затем отменить - вам не нужно сохранять отредактированный файл.)
См. Руководство Elisp, узел Using Debugger
для получения дополнительной информации.
Рекурсия как петля
Во всяком случае, думать о рекурсии как о петле. Определены два случая прекращения: (<= number 0)
и (= number 1)
. В этих случаях функция возвращает простое число.
В рекурсивном случае функция возвращает сумму этого числа и результат функции с number - 1
. В конце концов, функция будет вызываться либо 1
с числом, меньшим или равным нулю.
Отсюда рекурсивный результат:
(+ number (+ (1- number) (+ (1- (1- number)) ... 1)
Взять к примеру (triangle-using-cond 4)
. Давайте накопим окончательное выражение:
в первой итерации number
есть 4
, так что (> number 1)
ветка следует. Мы начинаем строить выражения (+ 4 ...
и вызвать функцию с (1- 4)
, то есть (triangle-using-cond 3)
.
сейчас number
есть 3
, и результат есть (+ 3 (triangle-using-cond 2))
. Общее выражение результата (+ 4 (+ 3 (triangle-using-cond 2)))
.
number
является в 2
настоящее время, так что выражение(+ 4 (+ 3 (+ 2 (triangle-using-cond 1))))
number
в 1
настоящее время, и мы берем (= number 1)
ветвь, в результате раздражения 1
. Целое выражение есть (+ 4 (+ 3 (+ 2 1)))
. Оценивать , что изнутри , и вы получите: (+ 4 (+ 3 3))
, (+ 4 6)
или просто 10
.
triangle-using-cond
с аргументом, который на 1 меньше любого числа. Условия идут в порядке a, b, а затем c - что бы ни совпадало сначала, это где доллар останавливается.