Vamos vs. Encadernação em Clojure
Pergunta
Eu entendo que eles são diferentes, desde um funciona para a criação *compile-path*
e um não. No entanto, eu preciso de ajuda com isso eles são diferentes.
let
cria um novo escopo com as ligações de dados, mas binding
...?
Solução
let
cria um alias de imutável escopo léxico para algum valor. binding
cria um escopo dinamicamente vinculativo para alguns Var
.
dinâmico significa que o código dentro de sua forma binding
e qualquer código que que as chamadas de código (mesmo se não no escopo léxico local) verá a nova ligação.
Dada:
user> (def ^:dynamic x 0)
#'user/x
binding
realmente cria uma ligação para um Var
dinâmica, mas let
apenas sombras do var com um alias local:
user> (binding [x 1] (var-get #'x))
1
user> (let [x 1] (var-get #'x))
0
binding
pode usar nomes qualificados (uma vez que opera em Var
s) e let
não pode:
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
ligações introduziu-let
não são mutáveis. ligações introduziu-binding
são thread-localmente mutável:
user> (binding [x 1] (set! x 2) x)
2
user> (let [x 1] (set! x 2) x)
; Evaluation aborted.
;; Invalid assignment target
ligação Lexical vs. dinâmico:
user> (defn foo [] (println x))
#'user/foo
user> (binding [x 1] (foo))
1
nil
user> (let [x 1] (foo))
0
nil
Outras dicas
Uma diferença mais sintático para deixar vs ligação:
Para a ligação, todos os valores iniciais são avaliados antes de qualquer um deles está ligado ao Vars. Isso é diferente do let, onde você pode usar o valor de um "apelido" anterior em uma definição 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
se liga um valor a um nome no ambiente global por thread
Como você mencionou, let
cria um novo espaço para ditas ligações.