宏不能引用外部变量吗?

本来以为宏只是展开一下,可以写出如下的代码:

macro |(fs...)
    ex = :($(first(fs))(x))
    for f in fs[2:end]
        ex = :($ex*$f(x))
    end
    :(x->$ex)
end

basis=[x->x^n for n=0:5];
IJ=[(@| i j)(2) for i in basis,j in basis];

其中 @| 就是将函数相乘,即 @| i j 等于 x->i(x)*j(x)
结果并不是预期的结果,展开后发现:

julia> @macroexpand [(@| i j)(2) for i in basis,j in basis]
:([((#85#x->begin
          #= REPL[286]:6 =#
          (Main.i)(#85#x) * (Main.j)(#85#x)
      end))(2) for i = basis, j = basis])

里面 i 和 j 是Main.i Main.j 并不是想要的局部的 i 和 j。

需要escape一下,可以读一下文档macro hygiene一节:

julia> macro |(fs...)
           ex = :($(first(fs))(x))
           for f in fs[2:end]
               ex = :($ex*$f(x))
           end
           esc(:(x->$ex))
       end
@| (macro with 1 method)

julia> @macroexpand [(@| i j)(2) for i in basis,j in basis]
:([((x->begin
          #= REPL[10]:6 =#
          i(x) * j(x)
      end))(2) for i = basis, j = basis])

julia> basis = [sin, cos]
2-element Array{Function,1}:
 sin
 cos

julia> [(@| i j)(2) for i in basis,j in basis]
2×2 Array{Float64,2}:
  0.826822  -0.378401
 -0.378401   0.173178

1 个赞

太感谢了 :blush:

这个是0.6的改动issue 15850,在函数里用宏要多留意一下escape.

好的好的,非常感谢