2009-11-21 122 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