Lassen Sie gegen Bindung in Clojure

69

Ich verstehe, dass sie unterschiedlich sind, da man für die Einstellung arbeitet *compile-path*und man nicht. Ich brauche jedoch Hilfe, warum sie anders sind.

leterstellt einen neuen Bereich mit den angegebenen Bindungen, aber binding...?

Carl
quelle

Antworten:

107

letErstellt einen unveränderlichen Alias ​​mit lexikalischem Gültigkeitsbereich für einen bestimmten Wert. bindingerstellt für einige eine Bindung mit dynamischem Gültigkeitsbereich Var.

Dynamische Bindung bedeutet, dass der Code in Ihrem bindingFormular und jeder Code, den dieser Code aufruft (auch wenn er nicht im lokalen lexikalischen Bereich liegt), die neue Bindung sehen.

Gegeben:

user> (def ^:dynamic x 0)
#'user/x

bindingErstellt tatsächlich eine dynamische Bindung für a Var, letschattiert die Variable jedoch nur mit einem lokalen Alias:

user> (binding [x 1] (var-get #'x))
1
user> (let [x 1] (var-get #'x))
0

bindingkann qualifizierte Namen verwenden (da es mit Vars arbeitet) und letkann nicht:

user> (binding [user/x 1] (var-get #'x))
1
user> (let [user/x 1] (var-get #'x))
; Evaluation aborted.
;; Can't let qualified name: user/x

leteingeführte Bindungen sind nicht veränderlich. bindingeingeführte Bindungen sind thread-lokal veränderbar:

user> (binding [x 1] (set! x 2) x)
2
user> (let [x 1] (set! x 2) x)
; Evaluation aborted.
;; Invalid assignment target

Lexikalische vs. dynamische Bindung:

user> (defn foo [] (println x))
#'user/foo
user> (binding [x 1] (foo))
1
nil
user> (let [x 1] (foo))
0
nil

Siehe auch Vars , lass .

Brian Carper
quelle
5
Dieses Plus en.wikipedia.org/wiki/… hat mein Verständnis wirklich erweitert. Danke mein Herr!
Carl
1
Das x muss mit dem dynamischen Hinweis ^: verbunden sein, um keinen Fehler auszulösen, glaube ich.
WeGi
12

Ein weiterer syntaktischer Unterschied zwischen let und bindung:

Für die Bindung werden alle Anfangswerte ausgewertet, bevor sie an die Variablen gebunden werden. Dies unterscheidet sich von let, wo Sie den Wert eines vorherigen "Alias" in einer nachfolgenden Definition verwenden können.

user=>(let [x 1 y (+ x 1)] (println y))
2
nil

user=>(def y 0)
user=>(binding [x 1 y (+ x 1)] (println y))
1
nil
Marc
quelle
Sie benötigen ^: dynamic, um x bis 0 (auch dynamisch) zu definieren, damit Ihr zweites Beispiel funktioniert.
John
9

binding bindet einen Wert an einen Namen in der globalen Umgebung pro Thread

Wie Sie bereits erwähnt haben, letwird ein neuer Bereich für diese Bindungen erstellt.

Yuval Adam
quelle