功能模板的宏:转义问题

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)

而更高级的用户仍然可以使用全功率.但是,如果您运行该代码,您将可以访问未定义的引用错误.我认为这是因为我没有正确地逃避表达,并且应该以某种方式逃避整个功能,但我不确定如何.

张实唯*_*张实唯 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
Run Code Online (Sandbox Code Playgroud)

答案很长:

  1. 关于卫生的事情

julia将为宏中定义的任何名称添加前缀,使其在其他任何地方都无法访问.esc将取消这些前缀,以便最终表达式中的名称与您编写的名称完全相同.所以请记住,只有esc在需要访问宏的这些变量时才使用,这不是你的例子.

  1. 用于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,没有在任何地方定义.

  1. 更好地使用函数而不是宏

通常,最好使用高阶函数来实现"函数模板",因为它们更容易阅读并且可以利用现代静态分析工具 - 尽管似乎Julia还没有一个:).写函数签名并传递它们似乎很烦人,但它们值得.