Использование «отладки 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 - что бы ни совпадало сначала, это где доллар останавливается.