Utilizzo di "debug printf"
È possibile lasciare che Emacs ti aiuti a capire modificando la definizione della funzione:
(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))))))
Basta aggiungere un (message ...)
posto per avere una traccia stampata nel *Messages*
buffer.
Usando Edebug
Posiziona il punto in qualsiasi punto all'interno della definizione della funzione e premi C-u C-M-x
per "strumento". Quindi valutare la funzione, ad esempio posizionando il punto dopo (triangle-using-cond 3)
e colpendo C-x C-e
.
Ora sei in modalità Edebug. Premi la barra spaziatrice per scorrere la funzione. I valori intermedi di ciascuna espressione sono mostrati nell'area dell'eco. Per uscire dalla modalità Edebug basta premere q
. Per rimuovere la strumentazione, posiziona un punto qualsiasi all'interno della definizione e premi C-M-x
per rivalutare la definizione.
Utilizzo del debugger standard di Emacs
M-x debug-on-entry triangle-using-cond
, quindi, quando triangle-using-cond
viene invocato, vieni inserito nel debugger (buffer *Backtrace*
) di Emacs .
Passa attraverso la valutazione usando d
(o c
per saltare tutte le valutazioni poco interessanti).
Per visualizzare lo stato intermedio (valori variabili, ecc.) È possibile utilizzare in e
qualsiasi momento. Viene richiesto di inserire un sexp per valutare e il risultato della valutazione viene stampato.
Mentre usi il debugger, mantieni una copia del codice sorgente visibile in un altro frame, in modo da poter seguire quello che sta succedendo.
È inoltre possibile inserire chiamate esplicite per immettere il debugger (più o meno punti di interruzione) in posizioni arbitrarie nel codice sorgente. Inserisci (debug)
o (debug nil SOME-SEXP-TO-EVALUATE)
. In quest'ultimo caso, quando viene inserito il debugger SOME-SEXP-TO-EVALUATE
viene valutato e il risultato viene stampato. (Ricorda che puoi inserire tale codice nel codice sorgente e utilizzarlo C-M-x
per valutarlo, quindi annullare: non è necessario salvare il file modificato.)
Vedere il manuale Elisp, nodo Using Debugger
per ulteriori informazioni.
Ricorsione come un ciclo
Ad ogni modo, pensa alla ricorsione come a un ciclo. Sono definiti due casi di risoluzione: (<= number 0)
e (= number 1)
. In questi casi la funzione restituisce un numero semplice.
Nel caso ricorsivo la funzione restituisce la somma di quel numero e il risultato della funzione con number - 1
. Alla fine, la funzione verrà chiamata con uno 1
o un numero minore o uguale a zero.
Il risultato del caso ricorsivo è quindi:
(+ number (+ (1- number) (+ (1- (1- number)) ... 1)
Prendi ad esempio (triangle-using-cond 4)
. Accumuliamo l'espressione finale:
nella prima iterazione number
è 4
, quindi il (> number 1)
ramo è seguito. Iniziamo a costruire un'espressione (+ 4 ...
e chiamiamo la funzione con (1- 4)
, ad es (triangle-using-cond 3)
.
ora number
è 3
e il risultato è (+ 3 (triangle-using-cond 2))
. L'espressione del risultato totale è (+ 4 (+ 3 (triangle-using-cond 2)))
.
number
è 2
ora, quindi l'espressione è(+ 4 (+ 3 (+ 2 (triangle-using-cond 1))))
number
è 1
ora e prendiamo il (= number 1)
ramo, risultando noioso 1
. L'intera espressione è (+ 4 (+ 3 (+ 2 1)))
. Valutare che dall'interno verso l'esterno e si ottiene: (+ 4 (+ 3 3))
, (+ 4 6)
, o semplicemente 10
.
triangle-using-cond
con l'argomento 1 in meno di qualunque sia il numero. Le condizioni vanno nell'ordine di a, b, e quindi c - qualunque cosa corrisponda per prima, è dove il dollaro si ferma.