我正在尝试理解Julia元编程文档中有关宏卫生的陈述。该文档声称:
Julia的宏展开器通过以下方式解决了这些问题。首先,宏结果中的变量被分类为本地变量或全局变量。如果变量被分配(而不是声明为全局变量)、声明为本地变量或用作函数参数名,则将其视为本地变量。否则,它被视为全局变量。然后将本地变量重命名为唯一名称(使用gensym()函数生成新符号),并在宏定义环境中解析全局变量。因此,两个以上的问题都得到了处理;宏的本地变量不会与任何用户变量冲突,time和println将引用标准库定义。
我编写了一个小程序来查看是否确实在宏定义环境中解析了全局变量。我编写了以下内容:
如果我正确理解了Julia文档,宏卫生的一部分是确保在宏返回表达式中调用的任何函数不会被调用者环境中同名函数劫持。但这正是在这里发生的事情,使用的函数
我原以为我必须使用
此外,我注意到宏结果中的变量
我该如何阅读文档以理解在此处不需要使用
编辑(澄清)
Julia的宏展开器通过以下方式解决了这些问题。首先,宏结果中的变量被分类为本地变量或全局变量。如果变量被分配(而不是声明为全局变量)、声明为本地变量或用作函数参数名,则将其视为本地变量。否则,它被视为全局变量。然后将本地变量重命名为唯一名称(使用gensym()函数生成新符号),并在宏定义环境中解析全局变量。因此,两个以上的问题都得到了处理;宏的本地变量不会与任何用户变量冲突,time和println将引用标准库定义。
我编写了一个小程序来查看是否确实在宏定义环境中解析了全局变量。我编写了以下内容:
f(x) = x + 100
macro g() # According to Julia docs, ...
:(f(x) + 5) # ... f is global, x is local, right?
end # if so, f should refer to the f above?
(function main()
local x = 3
f(x) = x - 100 # f in the call environment subtracts 100
println(@g()) # So why does this do -92?
end)()
如果我正确理解了Julia文档,宏卫生的一部分是确保在宏返回表达式中调用的任何函数不会被调用者环境中同名函数劫持。但这正是在这里发生的事情,使用的函数
f
是本地定义的函数。我原以为我必须使用
esc
才能使用调用点范围内的f
。但事实并非如此,为什么?此外,我注意到宏结果中的变量
x
被视为本地变量,因此应该为其生成一个新的gensymed变量名称,以避免与宏调用环境中的x
冲突。但这也没有发生!我该如何阅读文档以理解在此处不需要使用
esc
的原因?编辑(澄清)
根据文档,当我声明
f
是全局的而x
是局部的时,是因为我看到x
被用作函数参数。我理解x
既没有被写入也没有被声明为局部变量,它看起来确实是全局的,但是那些文档声称函数参数也应该是全局的!我知道卫生常规中局部变量的gensymming确保了在宏调用者的上下文中具有相同名称的变量不会被意外地修改。然而,文档声称对于函数,在宏定义的上下文中可见的变量受到保护,以防止调用者使用自己的变量。这是让我感到困惑的部分,因为我的实验结果表明情况并非如此。