Pular para o conteúdo

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 inteiroyield 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 estourou

As quatro recusas#

Não vira salto quandoPorque
defer na açãoele roda na saída do quadro, e o salto reusa o quadro
o yield está dentro de monitoro handle precisa ver o que a chamada levanta
a recursão é indireta (fgf)a análise olha uma ação por vez
todo yield da ação é caudaela 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.