Using "printf debugging"
You could let Emacs help you understand by modifying the function definition:
(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))))))
Just add (message ...)
somewhere to have a trail printed to the *Messages*
buffer.
Using Edebug
Place point anywhere inside the function definition and hit C-u C-M-x
to "instrument" it. Then evaluate the function, e.g. by placing point after (triangle-using-cond 3)
and hitting C-x C-e
.
You are now in Edebug mode. Hit the space bar to step through the function. The intermediate values of each expression are shown in the echo area. To exit Edebug mode just hit q
. To remove the instrumentation, put point anywhere inside the definition and hit C-M-x
to re-evaluate the definition.
Using the standard Emacs debugger
M-x debug-on-entry triangle-using-cond
, then, when triangle-using-cond
is invoked, you are placed in the Emacs debugger (buffer *Backtrace*
).
Step through the evaluation using d
(or c
to skip through any uninteresting evaluations).
To see intermediate state (variable values, etc.) you can use e
anytime. You are prompted to enter a sexp to evaluate, and the evaluation result is printed.
While you use the debugger, keep a copy of the source code visible in another frame, so you can follow what's going on.
You can also insert explicit calls to enter the debugger (more or less breakpoints) at arbitrary places in the source code. You insert (debug)
or (debug nil SOME-SEXP-TO-EVALUATE)
. In the latter case, when the debugger is entered SOME-SEXP-TO-EVALUATE
is evaluated and the result is printed. (Remember that you can insert such code into the source code and use C-M-x
to evaluate it, then undo - you need not save the edited file.)
See the Elisp manual, node Using Debugger
for more information.
Recursion as a loop
Anyway, think of recursion as a loop. There are two termination cases defined: (<= number 0)
and (= number 1)
. In these cases the function returns a simple number.
In the recursive case the function returns the sum of that number and the result of the function with number - 1
. Eventually, the function will be called with either 1
or a number smaller than or equal to zero.
The recursive case result is hence:
(+ number (+ (1- number) (+ (1- (1- number)) ... 1)
Take for example (triangle-using-cond 4)
. Let's accumulate the final expression:
in the first iteration number
is 4
, so the (> number 1)
branch is followed. We start building an expression (+ 4 ...
and call the function with (1- 4)
, i.e. (triangle-using-cond 3)
.
now number
is 3
, and the result is (+ 3 (triangle-using-cond 2))
. The total result expression is (+ 4 (+ 3 (triangle-using-cond 2)))
.
number
is 2
now, so the expression is (+ 4 (+ 3 (+ 2 (triangle-using-cond 1))))
number
is 1
now, and we take the (= number 1)
branch, resulting in a boring 1
. The whole expression is (+ 4 (+ 3 (+ 2 1)))
. Evaluate that from the inside out and you get: (+ 4 (+ 3 3))
, (+ 4 6)
, or just 10
.