Chamada de cauda
yield f(…) vira salto, e a recursão perde o teto — com as quatro recusas que mantêm isso correto.
Cada chamada de ação ocupa um quadro, e o teto é de mil quadros: uma recursão de cinco mil níveis estoura, mesmo sem nada de infinito. Mas quando a chamada é o retorno inteiro — yield f(…) —, não há nada a fazer depois dela, e o quadro só existiria para repassar o resultado. O compilador troca a chamada por um salto, reaproveitando o quadro.
dataforge
action contar(n, acc := 0):
given n is 0:
yield acc
yield contar(n - 1, acc + 1) // cauda: nada depois dela
assert contar(200000) is 200000 // sem teto
action ingenua(n):
given n is 0:
yield 0
yield 1 + ingenua(n - 1) // NÃO é cauda: ainda falta somar 1
estourou := no
monitor:
ingenua(5000)
handle StackOverflowError:
estourou := yes
assert estourouAs quatro recusas#
| Não vira salto quando | Porque |
|---|---|
há defer na ação | ele roda na saída do quadro, e o salto reusa o quadro |
o yield está dentro de monitor | o handle precisa ver o que a chamada levanta |
a recursão é indireta (f → g → f) | a análise olha uma ação por vez |
todo yield da ação é cauda | ela nunca devolveria: virar laço infinito calado seria pior que o erro |
A última é a mais importante: sem ela, action r(n): yield r(n + 1) deixaria de dar StackOverflowError e passaria a travar para sempre.