2009-10-06 12 views
65

Capisco che siano diversi poiché uno funziona per l'impostazione *compile-path* e uno no. Tuttavia, ho bisogno di aiuto per spiegare perché sono diversi.Let vs. Binding in Clojure

let crea un nuovo ambito con le associazioni specificate, ma binding ...?

risposta

99

let crea un alias immutabile con lo scope lessicale per un certo valore. binding crea un binding con ambito dinamico per alcuni Var.

Il collegamento dinamico significa che il codice all'interno del modulo binding e qualsiasi codice che tale codice chiama (anche se non nell'ambito lessicale locale) vedrà la nuova associazione.

Dato:

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

binding crea in realtà una dinamica vincolante per un Var ma let ombre solo la var con un alias locale:

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

binding possono usare nomi qualificati (dal momento che opera su Var s) e let non possono:

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 - i collegamenti introdotti non sono modificabili. binding attacchi -introduced sono thread-localmente mutevole:

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

lessicale vs dinamica vincolante:

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

Vedi anche Vars, let.

+4

Questo plus http://en.wikipedia.org/wiki/Scope_(programming)#Static_versus_dynamic_scoping mi ha davvero aiutato. Grazie Signore! – Carl

+0

La x deve essere associata con il suggerimento ^: dinamico per non generare un errore, io credo. – WeGi

8

binding si lega un valore a un nome nell'ambiente globale pro-filo

Come lei ha ricordato, let crea un nuovo ambito per detti attacchi.

10

Ancora una differenza sintattica per Let vs rilegatura:

Per la rilegatura, tutti i valori iniziali vengono valutati prima di qualsiasi di essi sono legati al Vars. Questo è diverso da let, dove puoi usare il valore di un precedente "alias" in una definizione successiva.

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 
+0

È necessario ^: dinamico per definire x su 0 (anche dinamicamente) per far funzionare il secondo esempio. – John