Clojure中的变量范围+ eval

时间:2011-06-03 00:05:03

标签: binding clojure eval let

在Clojure中,

(def x 3)
(eval '(prn x))

打印3,而

(let [y 3]
   (eval '(prn y)))

(binding [z 3] (eval '(prn z)))

生成'无法解析var'异常。

根据http://clojure.org/evaluationevalload-string等生成临时命名空间以评估其内容。因此,我希望上述代码示例都不起作用,因为(def x 3)是在我当前的命名空间中完成的,而不是eval创建的。{/ p>

  1. 为什么第一个代码示例工作而不是最后两个?
  2. 如何eval使用绑定变量的表单而不使用def
  3. 谢谢!

1 个答案:

答案 0 :(得分:15)

1:

这不起作用的原因是(或多或少)在您链接的页面上给出:

It is an error if there is no global var named by the symbol […]

  

[...]

     
      
  1. 在当前命名空间中完成查找以查看是否存在映射   从符号到变量。如果是这样的话   value是绑定的值   由符号引用的var。

  2.   
  3. 这是一个错误。

  4.   

eval评估空(CL-lingo中的null)词汇环境中的表单。这意味着,您无法从调用者的作用域访问词法变量绑定。此外,binding为现有变量创建新的绑定,这就是为什么你不能“单独”使用它,而没有declare d或def你尝试绑定的变量。此外,词汇变量(至少在CL中,但如果Clojure不是这样,我会感到惊讶)已经在运行时停止存在 - 它们被转换为地址或值。

有关此主题,请参阅我的older post

2:

因此,您必须使用动态变量。您可以避免显式def,但您仍然至少需要declare它们(def的var名称没有绑定):

user=> (declare ^:dynamic x)
#'user/x
user=> (binding [x 10] (eval '(prn x)))
10
nil

顺便说一句:我想你知道为什么你需要eval,并且当其他解决方案合适时,它的使用是considered evil