Clojure中的词法/动态范围 - 重新定义var时的范围

时间:2014-11-22 08:19:26

标签: clojure

我花了一整天的时间研究Clojure(和Lisp)中的词法和动态范围。当我以为我终于明白了,我做了这个例子并且非常惊讶它没有回复我的预期:

(def non-dynamic-var "this is a non dynamic var")
(def ^:dynamic dynamic-var "this is a dynamic var")

(defn function-using-dynamic-var []
  (println dynamic-var))

(defn function-using-non-dynamic-var []
  (println non-dynamic-var))

(defn some-function []

  (function-using-dynamic-var)
  ;; dynamically rebind dynamic-var
  (binding [dynamic-var "this is some new content for the dynamic var"]
    (function-using-dynamic-var))

  (function-using-non-dynamic-var)
  ;; locally rebind non-dynamic-var
  (let [non-dynamic-var "this is some new content that won't be used"]
    (function-using-non-dynamic-var))
  ;; lexically rebind non-dynamic-var
  (def non-dynamic-var "this is some new content that won't be used")
  (function-using-non-dynamic-var))

我正在声明一个普通和动态var,然后是一个使用每个var的相应函数然后我尝试如果重新绑定/重新定义变量会发生什么。来自some-function的呼叫的输出是:

this is a dynamic var
this is some new content for the dynamic var
this is a non dynamic var
this is a non dynamic var
this is some new content that won't be used

除最后一项外,输出符合预期。我无法理解为什么这会实际输出新值。由于我理解词法和动态范围,这应该仍然返回旧值,因为function-using-non-dynamic-varnon-dynamic-var中看到的函数在我看来应该仍然是第1行的定义,因为它是词汇范围。但显然我弄错了,任何人都能解释并理解它吗?

2 个答案:

答案 0 :(得分:1)

好。在Clojure中,所有defs都是全球范围的。所有。在函数some-function正文中包含defs。因此,在执行some-function时,最后两个表单创建non-dynamic-var的新全局定义,然后使用它调用函数,修改了var non-dynamic-var的全局根绑定。

答案 1 :(得分:0)

我认为这是由于def的实施方式。 def创建一个Var - “Vars提供了一种机制来引用可以在每个线程的基础上动态反弹(到新的存储位置)的可变存储位置。” - http://clojure.org/vars。需要注意的是Vars 可变存储位置,并且可以反弹。

“如果def表达式在当前命名空间中找不到被定义符号的实习条目,则会创建一个,否则它将使用现有的Var。” - http://clojure.org/vars#Interning

通过运行以下内容,您可以更简单地看到此行为:

(def non-dynamic-var "this is a non dynamic var")
(println non-dynamic-var)
(def non-dynamic-var "this is our new value for the the non dynamic var")
(println non-dynamic-var)

这将打印:

this is a non dynamic var
this is our new value for the the non dynamic var