将符号解析为宏与函数参数的规则是什么?

Mat*_*ick 5 variables macros clojure shadowing

我很惊讶地发现在Clojure 中alpha转换并不安全:

Clojure> ((fn [o] (o 3 2)) +)
5

Clojure> ((fn [or] (or 3 2)) +)
3

Clojure> ((fn [def] (def 3 2)) +)
java.lang.RuntimeException: First argument to def must be a Symbol
Run Code Online (Sandbox Code Playgroud)

(我预计所有三个片段都要评估为5).

当涉及阴影和宏以及特殊形式时,符号解析的规则是什么?

我正在使用Try Clojure上的版本.

Mat*_*ick 6

根据文档,你不能影子特殊形式:

符号已解决:

  • 如果它是名称空间限定的,则该值是由符号命名的全局变量的绑定值.如果没有符号命名的全局var,或者引用是不同命名空间中的非公共var,则会出错.
  • 如果它是包限定的,则值是由符号命名的Java类.如果没有符号命名的类,则会出错.
  • **否则,它不合格,并且以下第一项适用:
    1. 如果它命名一个特殊形式,它被认为是一种特殊形式,必须相应地使用.**
    2. 在当前命名空间中进行查找,以查看是否存在从符号到类的映射.如果是,则认为该符号命名Java类对象.请注意,类名通常表示类对象,但是以某些特殊形式特殊处理,例如'.' 和新的.
    3. 如果在本地范围内(即在函数定义中),则执行查找以查看它是否命名本地绑定(例如,函数参数或let-bound名称).如果是,则该值是本地绑定的值.
    4. 在当前命名空间中进行查找,以查看是否存在从符号到var的映射.如果是,则该值是符号引用的var的绑定值.
    5. 这是一个错误.

而且我不确定,但我解释这段(从同一页面)意味着你不能影子宏,或者:

宏是操纵表单的函数,允许语法抽象.如果调用的运算符是一个将全局var命名为宏函数的符号,则调用该宏函数并传递未评估的操作数形式.然后在其位置评估宏的返回值.

如果运算符不是特殊形式或宏,则该调用被视为函数调用.


mik*_*era 3

前两个对我来说都是 5(Eclipse 中的 Clojure 1.4/逆时针 REPL)。如果您得到 3,我怀疑 Try Clojure 中存在错误。

您应该能够在本地隐藏函数和宏名称(尽管这通常不是一个好主意,因为它可能会导致一些微妙且令人困惑的错误!)。

第三个不起作用,因为它def是一种特殊形式。特殊形式会受到 Clojure 阅读器和/或编译器的特殊对待,因此您无法隐藏它们。