Chr*_*kas 2 metaprogramming julia
我正在尝试为函数模板定义一个宏,即一个模板,您可以轻松地放入相关代码,但不希望向用户公开所有细节实现细节.例如,我想像这样将表达式放入更复杂的函数中:
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
Run Code Online (Sandbox Code Playgroud)
因此用户可以轻松插入一小部分逻辑(使用简化的API /文档):
easy_func = @make_complex_function begin
if u > 1
print("oh no! It happened!")
end
end
Run Code Online (Sandbox Code Playgroud)
而更高级的用户仍然可以使用全功率.但是,如果您运行该代码,您将可以访问未定义的引用错误.我认为这是因为我没有正确地逃避表达,并且应该以某种方式逃避整个功能,但我不确定如何.
简短的回答:不要使用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
Run Code Online (Sandbox Code Playgroud)
答案很长:
julia将为宏中定义的任何名称添加前缀,使其在其他任何地方都无法访问.esc将取消这些前缀,以便最终表达式中的名称与您编写的名称完全相同.所以请记住,只有esc在需要访问宏外的这些变量时才使用,这不是你的例子.
macroexpand帮助构建宏例如,如果你把它esc放在错误的地方,如下所示:
macro m(e)
quote
function f(x)
return $(esc(e))
end
end
end
Run Code Online (Sandbox Code Playgroud)
你会得到这样一个表达:
julia> macroexpand( :( @m x+1 ) )
quote # REPL[9], line 3:
function #1#f(#2#x) # REPL[9], line 4:
return x + 1
end
end
Run Code Online (Sandbox Code Playgroud)
你可以发现它f和它的参数以特殊的东西为前缀(因为它们没有被转义),而身体很简单x,没有在任何地方定义.
通常,最好使用高阶函数来实现"函数模板",因为它们更容易阅读并且可以利用现代静态分析工具 - 尽管似乎Julia还没有一个:).写函数签名并传递它们似乎很烦人,但它们值得.