Uso de "depuración de printf"
Puede dejar que Emacs lo ayude a comprender modificando la definición de la función:
(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))))))
Simplemente agregue un (message ...)
lugar para imprimir un rastro en el *Messages*
búfer.
Usando Edebug
Coloque el punto en cualquier lugar dentro de la definición de la función y presione C-u C-M-x
para "instrumentarlo". Luego evalúe la función, por ejemplo, colocando un punto después (triangle-using-cond 3)
y golpeando C-x C-e
.
Ahora estás en modo Edebug. Presiona la barra espaciadora para recorrer la función. Los valores intermedios de cada expresión se muestran en el área de eco. Para salir del modo Edebug solo presiona q
. Para eliminar la instrumentación, coloque el punto en cualquier lugar dentro de la definición y presione C-M-x
para reevaluar la definición.
Usando el depurador estándar de Emacs
M-x debug-on-entry triangle-using-cond
, luego, cuando triangle-using-cond
se invoca, se le coloca en el depurador de Emacs (búfer *Backtrace*
).
Avance por la evaluación usando d
(o c
para omitir cualquier evaluación no interesante).
Para ver el estado intermedio (valores variables, etc.) puede usarlo en e
cualquier momento. Se le solicita que ingrese un sexp para evaluar, y se imprime el resultado de la evaluación.
Mientras usa el depurador, mantenga una copia del código fuente visible en otro marco, para que pueda seguir lo que está sucediendo.
También puede insertar llamadas explícitas para ingresar el depurador (más o menos puntos de interrupción) en lugares arbitrarios en el código fuente. Usted inserta (debug)
o (debug nil SOME-SEXP-TO-EVALUATE)
. En el último caso, cuando se ingresa el depurador SOME-SEXP-TO-EVALUATE
se evalúa y se imprime el resultado. (Recuerde que puede insertar dicho código en el código fuente y utilizarlo C-M-x
para evaluarlo, luego deshacerlo; no necesita guardar el archivo editado).
Consulte el manual de Elisp, nodo Using Debugger
para obtener más información.
La recursión como un bucle
De todos modos, piense en la recursividad como un bucle. Hay dos casos de terminación definidos: (<= number 0)
y (= number 1)
. En estos casos, la función devuelve un número simple.
En el caso recursivo, la función devuelve la suma de ese número y el resultado de la función con number - 1
. Eventualmente, la función se llamará con 1
o con un número menor o igual a cero.
El resultado del caso recursivo es por lo tanto:
(+ number (+ (1- number) (+ (1- (1- number)) ... 1)
Toma por ejemplo (triangle-using-cond 4)
. Acumulemos la expresión final:
en la primera iteración number
es 4
, entonces (> number 1)
se sigue la rama. Comenzamos a construir una expresión (+ 4 ...
y llamamos a la función con (1- 4)
, es decir (triangle-using-cond 3)
.
ahora number
es 3
, y el resultado es (+ 3 (triangle-using-cond 2))
. La expresión de resultado total es (+ 4 (+ 3 (triangle-using-cond 2)))
.
number
es 2
ahora, entonces la expresión es(+ 4 (+ 3 (+ 2 (triangle-using-cond 1))))
number
es 1
ahora, y tomamos la (= number 1)
rama, lo que resulta en un aburrido 1
. Toda la expresión es (+ 4 (+ 3 (+ 2 1)))
. Evaluar que de adentro hacia afuera y se obtiene: (+ 4 (+ 3 3))
, (+ 4 6)
o simplemente 10
.
triangle-using-cond
con el argumento 1 menor que cualquiera que sea el número. Las condiciones van en orden de a, b, y luego c - lo que coincida primero, es donde se detiene el dinero.