Je comprends qu'ils sont différents, car on travaille pour définir *compile-path*
et l'autre non. Cependant, j'ai besoin d'aide pour comprendre pourquoi ils sont différents.
let
crée une nouvelle portée avec les liaisons données, mais binding
...?
let
crée un alias immuable à portée lexicale pour une certaine valeur. binding
crée une liaison à portée dynamique pour certains Var
.
La liaison dynamique signifie que le code à l'intérieur de votre formulaire binding
et tout code que ce code appelle (même s'il n'est pas dans la portée lexicale locale) verront la nouvelle liaison.
Donné:
user> (def ^:dynamic x 0)
#'user/x
binding
crée en fait une liaison dynamique pour un Var
mais let
n'observe le var qu'avec un alias local:
user> (binding [x 1] (var-get #'x))
1
user> (let [x 1] (var-get #'x))
0
binding
peut utiliser des noms qualifiés (car il fonctionne sur Var
s) et let
ne peut pas:
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
- les liaisons introduites ne sont pas modifiables. binding
- les liaisons introduites sont mutables localement par les threads:
user> (binding [x 1] (set! x 2) x)
2
user> (let [x 1] (set! x 2) x)
; Evaluation aborted.
;; Invalid assignment target
Reliure lexicale vs dynamique:
user> (defn foo [] (println x))
#'user/foo
user> (binding [x 1] (foo))
1
nil
user> (let [x 1] (foo))
0
nil
Encore une différence syntaxique pour let vs binding:
Pour la liaison, toutes les valeurs initiales sont évaluées avant qu'aucune d'entre elles ne soit liée aux variables. Ceci est différent de let, où vous pouvez utiliser la valeur d'un "alias" précédent dans une définition ultérieure.
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
lie une valeur à un nom dans l'environnement global par thread
Comme vous l'avez mentionné, let
crée une nouvelle portée pour lesdites liaisons.