Clojure non esegue l'ottimizzazione delle chiamate tail da solo: quando hai una funzione ricorsiva di coda e vuoi ottimizzarla, devi usare la forma speciale recur
. Allo stesso modo, se hai due funzioni reciprocamente ricorsive, puoi ottimizzarle solo utilizzando trampoline
.
Il compilatore Scala è in grado di eseguire TCO per una funzione ricorsiva, ma non per due funzioni reciprocamente ricorsive.
Ogni volta che ho letto su questi limiti, sono sempre stati attribuiti a qualche limite intrinseco al modello JVM. Non conosco praticamente nulla dei compilatori, ma questo mi imbarazza un po '. Consentitemi di prendere l'esempio da Programming Scala
. Qui la funzione
def approximate(guess: Double): Double =
if (isGoodEnough(guess)) guess
else approximate(improve(guess))
è tradotto in
0: aload_0
1: astore_3
2: aload_0
3: dload_1
4: invokevirtual #24; //Method isGoodEnough:(D)Z
7: ifeq
10: dload_1
11: dreturn
12: aload_0
13: dload_1
14: invokevirtual #27; //Method improve:(D)D
17: dstore_1
18: goto 2
Quindi, a livello di bytecode, uno ha bisogno solo di goto
. In questo caso, infatti, il duro lavoro è svolto dal compilatore.
What facility of the underlying virtual machine would allow the compiler to handle TCO more easily?
Come nota a margine, non mi aspetto che le macchine reali siano molto più intelligenti della JVM. Tuttavia, molte lingue che compilano codice nativo, come Haskell, non sembrano avere problemi con l'ottimizzazione delle chiamate tail (beh, Haskell può avere a volte a causa della pigrizia, ma questo è un altro problema).