binding - Deje versus enlace en Clojure
let (3)
Entiendo que son diferentes ya que uno funciona para establecer *compile-path*
y uno no. Sin embargo, necesito ayuda con por qué son diferentes.
let
crea un nuevo alcance con los enlaces dados, pero binding
...?
Una diferencia sintáctica más para let versus binding:
Para el enlace, todos los valores iniciales se evalúan antes de que cualquiera de ellos se vincule a los vars. Esto es diferente de let, donde puede usar el valor de un "alias" anterior en una definición posterior.
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
binding
vincula un valor a un nombre en el entorno global por subproceso
Como mencionaste, crea un nuevo alcance para dichas vinculaciones.
let
crea un alias inmutable de ámbito léxico para algún valor. binding
crea un enlace de ámbito dinámico para algunos Var
.
La vinculación dinámica significa que el código dentro de su formulario de binding
y cualquier código que llame ese código (incluso si no está en el alcance léxico local) verá el nuevo enlace.
Dado:
user> (def ^:dynamic x 0)
#''user/x
binding
realmente crea un enlace dinámico para un Var
pero solo let
sombrear la var con un alias local:
user> (binding [x 1] (var-get #''x))
1
user> (let [x 1] (var-get #''x))
0
binding
puede usar nombres calificados (ya que opera en Var
s) y let
puede:
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
let
las consolidaciones introducidas no sean mutables. binding
-enlaces introducidos son thread-local mutable:
user> (binding [x 1] (set! x 2) x)
2
user> (let [x 1] (set! x 2) x)
; Evaluation aborted.
;; Invalid assignment target
Enlace léxico vs. dinámico:
user> (defn foo [] (println x))
#''user/foo
user> (binding [x 1] (foo))
1
nil
user> (let [x 1] (foo))
0
nil