2009-11-21 127 views
16

尽管我已经使用了Clojure,但我没有详细看过范围规则。当我阅读文件时,我感到更加困惑。 我做了一个小测试来测试作用域分辨率,并且在复杂性方面表现出色。有人可以解释Clojure使用的意图和各种规则吗?Clojure中的范围规则

(def x 1) 

(defn dummy-fn2[] 
    (+ x 1))   

(defn dummy-fn[] 
    (println "entering function: " x) 
     (let [x 100] 
     (println "after let: " x) 
     (let [x (dummy-fn2)] 
      (println "after let and dummy2: " x) 
      (binding [x 100] 
      (println "after binding: " x) 
      (let [x (dummy-fn2)] 
       (println "after binding and dummy2: " x)))))) 

1:2 foo=> (dummy-fn) 
entering function: 1 
after let: 100 
after let and dummy2: 2 
after binding: 2 
after binding and dummy2: 101 
nil 
+3

为了避免重复的文件,或许你可以描述你期望什么,以及为什么它是从实际发生的情况不同。 – 2009-11-21 03:39:59

回答

14

Clojure中使用的符号都词法范围let动态范围binding为瓦尔 退房Clojure的vars文档。

  • “进入功能”:做得很好!符号x解析为var,这是抓取var x的“根绑定”。
  • “放过后”:本地绑定覆盖了var,符号x现在是100而不是var。
  • “Let和dummy2后”:在伪FN2的x指VAR的x,所以它使用根x的结合和比返回的一个以上(+ 11)
  • “后结合“:棘手的一个!绑定动态地将名为x的变量(它是1)的根绑定替换为100,但本地符号x不再是变量,因此您可以获得本地绑定。
  • “结合和dummy2后”:用100的结合所取代了var x的根值和该返回比那(+ 100 1)
+0

它看起来像绑定替换“var与名称x”,而不是“符号x解析为var”这是正确的吗? – 2009-11-21 04:41:38

+0

“var与名称x”是什么意思? – 2009-11-21 07:35:43

+0

无论哪个var返回(解析'x)。 – 2009-11-21 09:28:33

22

let阴影顶层瓦尔x用当地xlet不会创建Var或影响顶层Var;它会绑定一些符号,以便将该符号的本地引用替换为绑定值letlet具有词汇范围,因此其绑定仅在let表单本身中可见(不在let内调用的函数中)。

binding临时(线程本地)更改顶级Var x的值,就是这么做。如果有一个let绑定,binding在决定要更改哪个值时看不到它(并且let的绑定不是变量,也不可更改,所以这是一件好事或它会给你一个错误)。并且binding不会掩盖letbinding具有动态范围,因此其对顶级变量的影响在binding表单以及从binding表单内调用的任何函数中都可见。

访问的老式x值会给你什么是绑定的堆栈的顶部,任x最嵌套let结合的值(或功能paramater称为x,或一些价值x被替换如果您使用自己的宏或其他可能性),并且如果没有其他绑定,则仅默认使用顶级变量Var x的当前值。

即使顶层瓦尔xlet结合的x掩盖,你可以随时通过@#'x访问顶层无功。试试这个版本,也许会更有意义:

(def x 1) 

(defn dummy-fn2[] 
    (println "x from dummy-fn2:" x) 
    (+ x 1)) 

(defn dummy-fn[] 
    (println "entering function:" x) 
    (println "var x:" @#'x) 
    (dummy-fn2) 
    (println "---") 
    (let [x 100] 
    (println "after let:" x) 
    (println "var x:" @#'x) 
    (dummy-fn2) 
    (println "---") 
    (let [x (dummy-fn2)] 
     (println "after let and dummy-fn2:" x) 
     (println "var x:" @#'x) 
     (dummy-fn2) 
     (println "---") 
     (binding [x 888] 
     (println "after binding:" x) 
     (println "var x:" @#'x) 
     (dummy-fn2) 
     (println "---") 
     (let [x (dummy-fn2)] 
      (println "after binding and dummy2:" x) 
      (println "var x:" @#'x) 
      (dummy-fn2) 
      (println "---")))))) 

给出:

entering function: 1 
var x: 1 
x from dummy-fn2: 1 
--- 
after let: 100 
var x: 1 
x from dummy-fn2: 1 
--- 
x from dummy-fn2: 1 
after let and dummy-fn2: 2 
var x: 1 
x from dummy-fn2: 1 
--- 
after binding: 2 
var x: 888 
x from dummy-fn2: 888 
--- 
x from dummy-fn2: 888 
after binding and dummy2: 889 
var x: 888 
x from dummy-fn2: 888 
--- 
+0

我得到'IllegalStateException当我运行此代码时不能动态绑定非动态var'。它通过用'let'替换'binding'或者使用'(def ^:dynamic x 1)'来解决 – dkinzer 2014-01-24 16:18:47