Usando "depuração printf"
Você pode deixar o Emacs ajudá-lo a entender, modificando a definição da função:
(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 adicionar um (message ...)lugar para imprimir uma trilha no *Messages*buffer.
Usando Edebug
Coloque o ponto em qualquer lugar dentro da definição da função e pressione C-u C-M-x"instrumentar". Em seguida, avalie a função, por exemplo, colocando o ponto depois (triangle-using-cond 3)e pressionando C-x C-e.
Agora você está no modo Edebug. Pressione a barra de espaço para percorrer a função. Os valores intermediários de cada expressão são mostrados na área de eco. Para sair do modo Edebug, basta pressionar q. Para remover a instrumentação, coloque um ponto em qualquer lugar dentro da definição e pressione C-M-xpara reavaliar a definição.
Usando o depurador Emacs padrão
M-x debug-on-entry triangle-using-cond, quando triangle-using-condfor chamado, você será colocado no depurador Emacs (buffer *Backtrace*).
Passe pela avaliação usando d(ou cpara pular as avaliações desinteressantes).
Para ver o estado intermediário (valores variáveis, etc.), você pode usar a equalquer momento. Você é solicitado a inserir um sexp para avaliar e o resultado da avaliação é impresso.
Enquanto você usa o depurador, mantenha uma cópia do código-fonte visível em outro quadro, para poder acompanhar o que está acontecendo.
Você também pode inserir chamadas explícitas para inserir o depurador (mais ou menos pontos de interrupção) em locais arbitrários no código-fonte. Você insere (debug)ou (debug nil SOME-SEXP-TO-EVALUATE). No último caso, quando o depurador é inserido, SOME-SEXP-TO-EVALUATEé avaliado e o resultado é impresso. (Lembre-se de que você pode inserir esse código no código-fonte e usá C-M-x-lo para avaliá-lo e desfazer - você não precisa salvar o arquivo editado.)
Consulte o manual do Elisp, nó Using Debuggerpara obter mais informações.
Recursão como um loop
Enfim, pense em recursão como um loop. Existem dois casos de rescisão definidos: (<= number 0)e (= number 1). Nesses casos, a função retorna um número simples.
No caso recursivo, a função retorna a soma desse número e o resultado da função com number - 1. Eventualmente, a função será chamada com um 1ou um número menor ou igual a zero.
O resultado do caso recursivo é, portanto:
(+ number (+ (1- number) (+ (1- (1- number)) ... 1)
Tome por exemplo (triangle-using-cond 4). Vamos acumular a expressão final:
na primeira iteração numberé 4, então a (> number 1)ramificação é seguida. Começamos a construir uma expressão (+ 4 ...e chamamos a função com (1- 4), ie (triangle-using-cond 3).
agora numberé 3e o resultado é (+ 3 (triangle-using-cond 2)). A expressão total do resultado é (+ 4 (+ 3 (triangle-using-cond 2))).
numberé 2agora, então a expressão é(+ 4 (+ 3 (+ 2 (triangle-using-cond 1))))
numberé 1agora, e tomamos o (= number 1)ramo, resultando em um tédio 1. Toda a expressão é (+ 4 (+ 3 (+ 2 1))). Avaliar que de dentro para fora e você tem: (+ 4 (+ 3 3)), (+ 4 6), ou apenas 10.
triangle-using-condcom o argumento 1 menor que qualquer que seja o número. As condições vão na ordem de a, bec, e c - o que corresponder primeiro, é onde o dinheiro para.