范围内的表达式和变量在Julia模块中的宏

5
由于某种原因,我必须在宏中放置quote...end块,并且ex是通过程序生成的。这段代码可以正常工作。
macro addsum_out()
  quote
    ex = :(x+y)
    sum(eval(ex))
  end
end

x = [1 1 1]
y = [2 2 2]

z2 = @addsum_out

当将宏放置在模块中时,它不再起作用:

module MyModule

export @addsum

macro addsum()
  quote
    ex = :(x+y)
    sum(eval(ex))
  end
end

end

using MyModule
x = [1 1 1]
y = [2 2 2]    
z = @addsum

It says:

ERROR: LoadError: UndefVarError: x not defined

我认为我应该在某个地方放置esc,以便在模块外的主范围内评估表达式ex。我该如何处理这个问题?


4
不应在宏中使用 eval。你想做什么? - David P. Sanders
2
eval 在模块全局范围内运行。看一下 macroexpand( :(@addsum) ) 并注意到 MyModule.eval。无论如何,这是完全不必要的。你应该返回 esc(:(x + y)) - Isaiah Norton
1个回答

5
问题在于模块内的宏引用 x 将会在该模块中查找 x,例如 MyModule.x
这是元编程中的一部分,被称为宏卫生
要防止发生宏卫生,您需要使用 esc(x) -- 这意味着它将使用调用站点中作用域内的 x。
您的完整解决方案可能如下所示:
macro addsum_out()
  quote
    esc(x) + esc(y)
  end
end

更简洁地说:
macro addsum_out()
  :(  esc(x) + esc(y)  )
end

请注意,这与执行esc( :(x+y) )稍有不同,因为这将转义+函数。也就是说,包含此宏的模块可能会对+进行重载,如果要使用此重载,则不要转义+,否则请转义!
我曾经在一份指南中讨论过这个问题:
https://github.com/p-i-/MetaGuideJulia/wiki#example-swap-macro-to-illustrate-esc

1
你的意思是 :( $(esc(:x)) + $(esc(:y)) ) - tim
1
另外,您可以使用esc(Expr(:call,+,:x,:y)) - tim

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接