如何定义一个Julia宏来定义一个宏?

5

我原以为这样会起作用:

macro meta_meta(x,y)
  :(macro $x(arg) :($($y) + $arg) end)
end

预期的行为是调用@meta_meta(f,2)应该等同于macro f(arg) :(2 + $arg) end 换句话说:
julia> @meta_meta(f,2)
julia> @f(3)
5

相反我得到:

ERROR: syntax: invalid macro definition

我有些不知道该如何继续。我发现这个宏的表达式树与手动生成@f并检查其表达式树时得到的表达式树不同,我尝试了几次@meta_meta,但我无法弄清楚如何改变我的定义以使其正常工作。


1
使用此链接作为示例:https://discourse.julialang.org/t/def-macro-generator-broken-on-master/1096/3?u=chrisrackauckas。你可能需要转义某些内容。 - Chris Rackauckas
谢谢指点!那应该可以解决问题。我有机会弄清楚了就试一下。 - HaberdashPI
1个回答

6

当涉及到引用内部的引用时,宏卫生有点棘手。通常我发现唯一的方法是完全拒绝宏卫生,并广泛使用 gensym 进行模拟。

然而,在您的简化示例中,将内部引用转换为 Expr 是很简单的:

julia> macro meta_meta(x, y)
           :(macro $(esc(x))(arg) Expr(:call, :+, $(esc(y)), esc(arg)) end)
       end
@meta_meta (macro with 1 method)

julia> @meta_meta f 2
@f (macro with 1 method)

julia> @f 3
5

如果事情变得更加复杂,我上面提到的方法涉及使用esc关闭宏卫生。这意味着我们必须自己进行卫生处理,因此需要使用gensym

julia> macro meta_meta(x, y)
           arg = gensym()
           esc(:(macro $x($arg) :($$y + $$arg) end))
       end
@meta_meta (macro with 1 method)

julia> @meta_meta f 2
@f (macro with 1 method)

julia> @f 3
5

谢谢!Chris的评论让我接近答案,但还没有完全解决。我一直遇到这个问题。这让我很惊讶,因为你的第二个解决方案没有遇到这个问题。我猜如果你转义整个表达式,那么关于转义参数的错误就不会出现了。 - HaberdashPI
@HaberdashPI 哦,是的,在我的第一个解决方案中,我最初忘记转义 arg。但它也没有遇到这个问题;我们实际上并没有转义任何函数参数名称。我已经更新了我的答案。 - Fengyang Wang

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