Clojure 中的变量作用域 + eval

2024-02-18

在 Clojure 中,

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

打印 3,而

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

and

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

生成“无法解析 var”异常。

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

  1. 为什么第一个代码示例可以工作,而后两个则不行?
  2. 我怎么能够eval具有绑定变量而不使用的形式def?

Thanks!


1.:

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

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

And:

[…]

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

  2. 这是一个错误。

eval评估空(null http://www.ai.mit.edu/projects/iiip/doc/CommonLISP/HyperSpec/Body/glo_n.html#null_lexical_environment在 CL-lingo 中)词汇环境。这意味着您无法从调用者的范围访问词法变量绑定。还,binding为现有变量创建新的绑定,这就是为什么你不能“单独”使用它,而不需要declared or def编辑您尝试绑定的变量。此外,词法变量(至少在 CL 中,但如果 Clojure 不是这种情况,我会感到惊讶)在运行时已经不再存在——它们被转换为地址或值。

另请参阅我的较旧的帖子 https://stackoverflow.com/questions/2575262/executing-a-dynamically-bound-function-in-clojure/2575425#2575425关于这个话题。

2.:

所以,你必须使用动态变量。你可以避免显式的def,但你至少还需要declare他们(其中def不带绑定的 var 名称):

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

顺便说一句:我想你知道为什么需要 eval,并且它的用途是被认为是邪恶的 https://stackoverflow.com/questions/2571401/why-exactly-is-eval-evil当其他解决方案合适时。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Clojure 中的变量作用域 + eval 的相关文章

随机推荐