Пусть против.Связывание в Clojure
Вопрос
Я понимаю, что они разные, так как один работает для настройки *compile-path*
а один нет.Однако мне нужна помощь, почему они разные.
let
создает новую область видимости с заданными привязками, но binding
...?
Решение
let
создает неизменяемый псевдоним с лексической областью действия для некоторого значения. binding
создает привязку с динамической областью действия для некоторых Var
.
Динамическая привязка означает, что код внутри вашего binding
form, и любой код, который этот код вызывает (даже если он не находится в локальной лексической области видимости), увидит новую привязку.
Данный:
user> (def ^:dynamic x 0)
#'user/x
binding
фактически создает динамическую привязку для Var
но let
только затеняет переменную с локальным псевдонимом:
user> (binding [x 1] (var-get #'x))
1
user> (let [x 1] (var-get #'x))
0
binding
может использовать полные имена (поскольку он работает с Var
песок let
не мочь:
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
-введенные привязки не изменяемы. binding
-введенные привязки изменяемы локально в потоке:
user> (binding [x 1] (set! x 2) x)
2
user> (let [x 1] (set! x 2) x)
; Evaluation aborted.
;; Invalid assignment target
Лексический против.динамическая привязка:
user> (defn foo [] (println x))
#'user/foo
user> (binding [x 1] (foo))
1
nil
user> (let [x 1] (foo))
0
nil
Другие советы
Еще одно синтаксическое различие между let и привязкой:
При привязке все начальные значения оцениваются до того, как какое-либо из них будет привязано к переменным.Это отличается от let, где вы можете использовать значение предыдущего «псевдонима» в последующем определении.
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
привязывает значение к имени в глобальной среде каждого потока
Как вы упомянули, let
создает новую область для указанных привязок.