Nicht Ihre Beispiele werden schneller, weil, wenn Sie verwenden recur
Sie bereits den Compiler sagen, dass Sie einen Schwanz rekursive Funktion haben und dies ermöglicht es dem Compiler-Byte-Code zu generieren, die goto
(wie ein normaler Imperativ loop) verwendet
Es gibt natürlich einige Vorteile, wenn die JVM die Tail Call Optimierung erhält.
Sie gewohnt haben, um mehr wiederholen zu verwenden (wenn Sie nicht wollen), so können Sie eine Funktion wie diese (a Schwanz rekursive Funktion)
(defn testfn [n] (when (not= 1000 n) (testfn n)))
schreiben Nowdays die JVM nicht in der Lage ist zu erkennen, Schwanzrekursion. Mit dem Zusatz von Endrekursion Optimierung der JVM der Lage, die Funktion siehe oben, als ob Sie das geschrieben hatten (und daher zwingend notwendig, Schleife Geschwindigkeit zu erhalten):
(defn testfn [n] (when (not= 1000 n) (recur n)))
Damit nicht so groß von einer Verbesserung, aber es ist ein anderes Fall, wo die Tail-Call-Optimierung wirklich großartig ist.
Wenn Sie Funktionen haben, die sich gegenseitig aufrufen (manchmal sogar mehr als zwei) und die nicht auf dem Stack halten müssen (sind rekursiv), kann die JVM sie optimieren. Dies ist jetzt nicht möglich, da Sie recur
nicht sagen können, um zu einer anderen Funktion zu springen. Hier ist ein Beispiel.
Wenn Sie dies mit einer großen Anzahl versuchen, wissen Sie, dass Sie den Stapel blasen werden, aber mit Tail-Call-Optimierung werden Sie nicht.
Ich habe auf wenig Ergänzung übrig. Es gibt eine Funktion trampoline
genannt, mit denen Sie tun dies bereits (mit einer kleinen Änderung im Programmierstil und etwas Overhead) Statt trampoline
zu erklären, ich werde Sie in ein Blog verweisen, die genau das tut:
http://pramode.net/clojure/2010/05/08/clojure-trampoline/