功能模板的宏:转义问题

时间:2016-10-15 03:08:08

标签: 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

因此用户可以轻松插入少量逻辑(使用简化的API /文档):

easy_func = @make_complex_function begin
   if u > 1
      print("oh no! It happened!")
    end
 end

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

1 个答案:

答案 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

长答案

  1. 关于卫生的事情
  2. julia将为宏中定义的任何名称添加前缀,使其无法在其他任何位置访问。 esc将取消这些前缀,以便最终表达式中的名称与您编写的名称完全相同。所以请记住,如果您需要访问外部宏,请使用esc,这不是您的示例。

    1. 使用macroexpand来帮助构建宏
    2. 例如,如果您将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,它没有在任何地方定义。

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