我正在尝试为函数模板定义一个宏,即一个模板,您可以轻松地放入相关代码但不想向用户公开所有细节实现细节。例如,我想像这样将表达式放到一个更复杂的函数中:
macro make_complex_function(ex)
quote
function (alg,f,t,u,k)
# Add some stuff on top
condition1 = false
condition2 = false
#...
#Put in the user's code
$(esc(ex))
# Put a footer
return some,stuff,here,long,annoying,list
end
end
end
因此用户可以轻松插入少量逻辑(使用简化的API /文档):
easy_func = @make_complex_function begin
if u > 1
print("oh no! It happened!")
end
end
虽然更高级的用户仍然可以使用全功率。但是,如果您运行该代码,您将可以访问未定义的引用错误。我认为这是因为我没有正确地逃避表达,并且应该以某种方式逃避整个功能,但我不确定如何。
答案 0 :(得分:5)
简短回答:请勿使用esc
或将其放在整个quote
块上。
julia> macro m(e)
quote
function f(x)
return $(e)
end
end
end
@m (macro with 1 method)
julia> f = @m x+1
#1#f (generic function with 1 method)
julia> f(2)
3
julia> macro m(e)
esc(quote
function f(x)
return $(e)
end
end)
end
@m (macro with 1 method)
julia> f = @m x+1
f (generic function with 1 method)
julia> f(2)
3
长答案:
julia将为宏中定义的任何名称添加前缀,使其无法在其他任何位置访问。 esc
将取消这些前缀,以便最终表达式中的名称与您编写的名称完全相同。所以请记住,如果您需要访问外部宏,请使用esc
,这不是您的示例。
macroexpand
来帮助构建宏例如,如果您将esc
放在错误的位置,如下所示:
macro m(e)
quote
function f(x)
return $(esc(e))
end
end
end
你会得到这样一个表达:
julia> macroexpand( :( @m x+1 ) )
quote # REPL[9], line 3:
function #1#f(#2#x) # REPL[9], line 4:
return x + 1
end
end
您可以发现f
及其参数的前缀是一个特殊的东西(因为它们没有被转义),而正文只是x
,它没有在任何地方定义。
通常,最好使用高阶函数来实现“函数模板”,因为它们更容易阅读并且可以利用现代静态分析工具 - 尽管似乎Julia还没有一个:)。写函数签名并传递它们似乎很烦人,但它们值得。