函数符号和局部变量

时间:2015-03-19 15:51:38

标签: clojure

以下代码按预期打印10张。

(def x 10)
(let [y 30] (eval (symbol "x")))

以下代码会产生异常:

 (let [y 20] (eval (symbol "y")))
 Unable to resolve symbol: y in this context

这是预期的(但令人困惑!)。根据文档,let定义的符号不属于任何名称空间,因此无法通过名称空间机制解析。

所以问题是:什么应该是局部变量的函数符号的等价物。

此外:

我认为Clojure编译器在内部调用每个标识符的函数符号来“实际”它,但正如上面的例子所示,情况并非如此。很好奇编译器实际上使用本地标识符做了什么。我假设当我在REPL中输入x时

 x

基本上按此处理:

 (deref (resolve (symbol "x")))

但显然局部变量并非如此。

PS:Symbols in Clojure不包括局部变量。

1 个答案:

答案 0 :(得分:1)

读取clojure编译器的所有输入,以形成列表,符号,关键字,数字和其他可读数据(例如,如果使用哈希映射文字,编译器将获得哈希映射)。

例如:

user=> (eval '(let [y 20] y))
20

在这种情况下,我们给编译器一个以符号let开头的列表(它解析为包含特殊形式的var宏)。

当你问"什么应该是局部变量的函数符号的等价物时,我首先想到的是你误解了函数symbol的含义。以下等同于我的初始示例:

user=> (eval (list (symbol "let") [(symbol "y") 20] (symbol "y")))
20

symbol仅对从字符串中获取var有用。事实上,这种用法通常是一种黑客攻击,并且表明你做错了。其主要目的是为编译器构造输入。编写从其词法范围获取绑定的表单最好通过编写函数并让用户传入要使用的值来完成。历史告诉我们,在调用者环境中隐式使用locals是混乱且容易出错的,并且它不是Clojure明确支持的功能(尽管肯定会有hack工作,这将基于无法保证表现的实现细节正确的语言的下一个版本。)