Macros julia元编程与nloops变量求值

Macros julia元编程与nloops变量求值,macros,julia,metaprogramming,Macros,Julia,Metaprogramming,我是元编程的noob,所以可能我不理解这一点。我认为@nloops宏在Base.Cartesian中的作用是,在维度未知的情况下,为循环编写任意数量的嵌套代码。在模块的文档中,给出了以下示例: @nloops 3 i A begin s += @nref 3 A i end 评估结果是 for i_3 = 1:size(A,3) for i_2 = 1:size(A,2) for i_1 = 1:size(A,1) s += A[i_1,

我是元编程的noob,所以可能我不理解这一点。我认为
@nloops
宏在
Base.Cartesian
中的作用是,在维度未知的情况下,为循环编写任意数量的嵌套代码。在模块的文档中,给出了以下示例:

@nloops 3 i A begin
    s += @nref 3 A i
end
评估结果是

for i_3 = 1:size(A,3)
    for i_2 = 1:size(A,2)
        for i_1 = 1:size(A,1)
            s += A[i_1,i_2,i_3]
        end
    end
end
在这里,数字3是先验的。然而,出于我的目的,以及我认为创建NLOOP的目的,嵌套级别的数量事先并不知道。所以我无法硬编码整数3。即使在文件中,也说明:

@nloops的(基本)语法如下:

  • 第一个参数必须是指定循环数的整数(不是变量)

如果我将整数值(例如传递给函数的数组的维数)赋给某个变量,nloops宏将不再工作:

b = 3
@nloops b i A begin
    s += @nref b A i
end
这将返回一个错误:

ERROR: LoadError: MethodError: no method matching _nloops(::Symbol, ::Symbol, ::Symbol, ::Expr)
Closest candidates are:
  _nloops(::Int64, ::Symbol, ::Symbol, ::Expr...) at cartesian.jl:43
...
我不知道如何让nloops将
b
变量计算为整数而不是符号。我查看了文档并尝试了
eval
以及其他函数和宏的各种迭代,但它要么被解释为符号,要么被解释为
Expr
。朱利安,写这篇文章的正确方法是什么?

参见:

生成的函数有点像宏,因为生成的表达式不会返回,而是在调用/调用时编译和执行,它还会看到参数的类型(当然还有它们的类型参数),即:

  • 在生成的函数中,
    A
    数组{T,N}
    不是数组的值
  • 所以
    T
    Int
    N
    3
在引用的表达式中,
N
插入表达式,语法为
$N
,计算结果为
3

julia> @generated function mysum(A::Array{T,N}) where {T,N}
           quote
               s = zero(T)
               @nloops $N i A begin
                   s += @nref $N A i
               end
               s
           end
       end
mysum (generic function with 1 method)

julia> mysum(A)
23.2791638775186
您可以构造表达式,然后对其求值,即:

julia> s = 0; n = 3;

julia> _3loops = quote
           @nloops $n i A begin
               global s += @nref $n A i
           end
       end
quote
    @nloops 3 i A begin
        global s += @nref(3, A, i)
    end
end

julia> eval(_3loops)

julia> s
23.2791638775186
我已经从AST中手动删除了
LineNumberNode
s以提高可读性(还有
MacroTools.prettify
,这可以为您完成)

在REPL中运行此示例需要在Julia 1.0中的循环内将
s
声明为
global

julia> s = 0; n = 3;

julia> _3loops = quote
           @nloops $n i A begin
               global s += @nref $n A i
           end
       end
quote
    @nloops 3 i A begin
        global s += @nref(3, A, i)
    end
end

julia> eval(_3loops)

julia> s
23.2791638775186