Ich kann 2 Möglichkeiten der Implementierung let
Bindings sehen. Erstens, wie aus SICP bekannt ist, kann let
als Lambda-Funktion implementiert werden. Dies ist bequem und einfach, aber unter Berücksichtigung der Tatsache, dass jedes Lambda (fn
) in JVM in separate Klasse übersetzt wird und die Anzahl let
im Durchschnitt Programm verwendet wird, scheint dies sehr, sehr teuer.Wie ist `Let` in Clojure implementiert und was ist sein Overhead?
Zweitens, let
Bindungen können direkt in lokale Java-Variablen übersetzt werden. Dies verursacht sehr wenig Overhead, aber das Speichern von Bindungen auf einem Stapel bricht die Sprachsemantik: In diesem Fall ist das Erstellen von Schließungen einfach unmöglich - gespeicherte Werte werden direkt nach dem Abwickeln des Stapels zerstört.
Was ist die tatsächliche Implementierung in Clojure? Auf entsprechende Zeilen in Clojure-Quelle zu zeigen, wird geschätzt.
Also verstehe ich Verschlussobjekt erstellt wird (und endgültige Variablen kopiert werden) nur bei Bedarf und für einfache Fälle vars bleiben nur auf dem Stapel? – ffriend
Ja, das ist so, wie es funktioniert. Wenn Sie interessiert sind, können Sie sich in: https://github.com/clojure/clojure/blob/master/src/jvm/clojure/lang/Compiler.java (obwohl es nicht besonders leicht ist herauszufinden, was Clojure ist) haben Compiler tut, es gibt eine Menge "Magie") – mikera
@ffriend Java hat Block-Bereichsvariablen (im Gegensatz zu Methodenbereich). Ich habe nicht untersucht, was der Clojure-Compiler tut, aber es scheint, dass * let * einfach durch einen Code-Block implementiert werden kann, der die endgültigen Variablen enthält. Ich bin nicht sicher, warum Sie denken, dass es mit einer Schließung umgesetzt worden wäre. –