Використання "налагодження 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
виклику вас розміщують у відладчику (буфері *Backtrace*
) Emacs .
Перегляньте оцінку за допомогою d
(або c
пропустіть будь-які нецікаві оцінки).
Для перегляду проміжного стану (змінних значень тощо) ви можете використовувати e
будь-коли. Вам буде запропоновано ввести сексоп для оцінки, і результат оцінки надрукується.
Під час використання налагоджувача зберігайте копію вихідного коду в іншому кадрі, щоб ви могли слідкувати за тим, що відбувається.
Ви також можете вставити явні дзвінки для введення налагоджувача (більш-менш точок перерви) у довільних місцях у вихідному коді. Ви вставляєте (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 - усе, що спочатку відповідає, саме там долар зупиняється.