Clojure führt die Tail-Call-Optimierung nicht alleine durch: Wenn Sie eine Tail-Recursive-Funktion haben und diese optimieren möchten, müssen Sie das spezielle Formular verwenden recur
. Wenn Sie zwei sich gegenseitig rekursive Funktionen haben, können Sie diese ebenfalls nur mithilfe von optimieren trampoline
.
Der Scala-Compiler kann TCO für eine rekursive Funktion ausführen, jedoch nicht für zwei sich gegenseitig rekursive Funktionen.
Wann immer ich über diese Einschränkungen gelesen habe, wurden sie immer einer Einschränkung zugeschrieben, die dem JVM-Modell eigen ist. Ich weiß so ziemlich nichts über Compiler, aber das verwirrt mich ein bisschen. Lassen Sie mich das Beispiel nehmen Programming Scala
. Hier die Funktion
def approximate(guess: Double): Double =
if (isGoodEnough(guess)) guess
else approximate(improve(guess))
wird übersetzt 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
Auf Bytecode-Ebene braucht man also nur goto
. In diesem Fall wird die harte Arbeit vom Compiler erledigt.
Welche Einrichtung der zugrunde liegenden virtuellen Maschine würde es dem Compiler ermöglichen, die Gesamtbetriebskosten einfacher zu handhaben?
Als Randnotiz würde ich nicht erwarten, dass tatsächliche Maschinen viel schlauer sind als die JVM. Trotzdem scheinen viele Sprachen, die mit nativem Code kompiliert werden, wie z. B. Haskell, keine Probleme mit der Optimierung von Tail Calls zu haben (Haskell kann manchmal aufgrund von Faulheit Probleme haben, aber das ist ein anderes Problem).