【问题标题】:Function symbol and local variables函数符号和局部变量
【发布时间】:2015-03-19 15:51:38
【问题描述】:

下面的代码按预期打印 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 不包括局部变量。

【问题讨论】:

    标签: clojure


    【解决方案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。事实上,这种用法通常是一种黑客行为,表明你做错了什么。它的主要目的是为编译器构造输入。编写一个从其词法范围获取绑定的表单最好通过编写一个函数并让用户传入要使用的值来完成。历史告诉我们,在调用者环境中隐式使用局部变量是混乱且容易出错的,而且这不是 Clojure 明确支持的功能(尽管肯定有一些 hack 可以工作,这将基于无法保证行为的实现细节正确的语言的下一个版本)。

    【讨论】:

    • 谢谢。没有计划编写这样的代码。只是想了解 Clojure:(eval (list 'let ['y 20] 'y))
    猜你喜欢
    • 1970-01-01
    • 2022-08-02
    • 1970-01-01
    • 1970-01-01
    • 2015-02-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-02-01
    相关资源
    最近更新 更多