Utilisation du "débogage printf"
Vous pouvez laisser Emacs vous aider à comprendre en modifiant la définition de la fonction:
(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))))))
Ajoutez simplement un (message ...)
endroit pour imprimer une trace dans le *Messages*
tampon.
Utiliser Edebug
Placez le point n'importe où à l'intérieur de la définition de la fonction et appuyez C-u C-M-x
dessus pour "l'instrumenter". Évaluez ensuite la fonction, par exemple en plaçant le point après (triangle-using-cond 3)
et en appuyant dessus C-x C-e
.
Vous êtes maintenant en mode Edebug. Appuyez sur la barre d'espace pour parcourir la fonction. Les valeurs intermédiaires de chaque expression sont affichées dans la zone d'écho. Pour quitter le mode Edebug, appuyez simplement sur q
. Pour supprimer l'instrumentation, placez le point n'importe où dans la définition et appuyez sur C-M-x
pour réévaluer la définition.
Utilisation du débogueur Emacs standard
M-x debug-on-entry triangle-using-cond
, puis, lorsque triangle-using-cond
est invoqué, vous êtes placé dans le débogueur Emacs (tampon *Backtrace*
).
Parcourez l'évaluation en utilisant d
(ou c
pour ignorer les évaluations sans intérêt).
Pour voir l'état intermédiaire (valeurs variables, etc.), vous pouvez utiliser à e
tout moment. Vous êtes invité à saisir un sexp à évaluer et le résultat de l'évaluation est imprimé.
Pendant que vous utilisez le débogueur, gardez une copie du code source visible dans un autre cadre, afin de pouvoir suivre ce qui se passe.
Vous pouvez également insérer des appels explicites pour entrer le débogueur (plus ou moins de points d'arrêt) à des endroits arbitraires dans le code source. Vous insérez (debug)
ou (debug nil SOME-SEXP-TO-EVALUATE)
. Dans ce dernier cas, lorsque le débogueur est entré SOME-SEXP-TO-EVALUATE
est évalué et le résultat est imprimé. (N'oubliez pas que vous pouvez insérer un tel code dans le code source et l'utiliser C-M-x
pour l'évaluer, puis annuler - vous n'avez pas besoin d'enregistrer le fichier modifié.)
Voir le manuel Elisp, node Using Debugger
pour plus d'informations.
Récursivité en boucle
Quoi qu'il en soit, pensez à la récursivité comme une boucle. Deux cas de résiliation sont définis: (<= number 0)
et (= number 1)
. Dans ces cas, la fonction renvoie un nombre simple.
Dans le cas récursif, la fonction renvoie la somme de ce nombre et le résultat de la fonction avec number - 1
. Finalement, la fonction sera appelée avec 1
un nombre ou un nombre inférieur ou égal à zéro.
Le résultat du cas récursif est donc:
(+ number (+ (1- number) (+ (1- (1- number)) ... 1)
Prenez par exemple (triangle-using-cond 4)
. Accumulons l'expression finale:
dans la première itération number
est 4
, donc la (> number 1)
branche est suivie. Nous commençons à construire une expression (+ 4 ...
et appelons la fonction avec (1- 4)
, ie (triangle-using-cond 3)
.
number
est maintenant 3
, et le résultat est (+ 3 (triangle-using-cond 2))
. L'expression du résultat total est (+ 4 (+ 3 (triangle-using-cond 2)))
.
number
est 2
maintenant, donc l'expression est(+ 4 (+ 3 (+ 2 (triangle-using-cond 1))))
number
est 1
maintenant, et nous prenons la (= number 1)
branche, ce qui entraîne un ennuyeux 1
. L'expression entière est (+ 4 (+ 3 (+ 2 1)))
. Évaluer que de l'intérieur et vous obtenez: (+ 4 (+ 3 3))
, (+ 4 6)
, ou tout simplement 10
.
triangle-using-cond
avec l'argument étant 1 de moins que le nombre. Les conditions vont dans l'ordre de a, b, puis c - tout ce qui correspond en premier, c'est là que l'argent s'arrête.