Clojure non esegue da solo l'ottimizzazione delle chiamate di coda: quando si dispone di una funzione ricorsiva di coda e si desidera ottimizzarla, è necessario utilizzare il modulo speciale recur
. Allo stesso modo, se hai due funzioni reciprocamente ricorsive, puoi ottimizzarle solo usando trampoline
.
Il compilatore Scala è in grado di eseguire il TCO per una funzione ricorsiva, ma non per due funzioni reciprocamente ricorsive.
Ogni volta che ho letto di queste limitazioni, sono sempre state attribuite a alcune limitazioni intrinseche al modello JVM. Non so praticamente nulla dei compilatori, ma questo mi confonde un po '. Vorrei prendere l'esempio da Programming Scala
. Ecco 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, basta uno goto
. In questo caso, infatti, il compilatore esegue il duro lavoro.
Quale funzione della macchina virtuale sottostante consentirebbe al compilatore di gestire il TCO più facilmente?
Come nota a margine, non mi aspetto che le macchine reali siano molto più intelligenti della JVM. Tuttavia, molte lingue che si compilano in codice nativo, come Haskell, non sembrano avere problemi con l'ottimizzazione delle chiamate di coda (beh, a volte Haskell può avere a causa della pigrizia, ma questo è un altro problema).