【问题标题】:julia metaprogramming and nloops variable evaluationJulia 元编程和 nloops 变量评估
【发布时间】:2018-10-29 00:28:58
【问题描述】:

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

@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 是先验已知的。然而,出于我的目的,并且出于我认为创建 nloops 的目的,嵌套级别的数量并不能提前知道。所以我无法对整数 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。写这个的正确的朱利安方式是什么?

【问题讨论】:

    标签: macros julia metaprogramming


    【解决方案1】:

    supplying the number of expressions:

    julia> A = rand(4, 4, 3)  # 3D array (Array{Int, 3})
    

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

    • 在生成的函数内部,AArray{T, N}不是数组的值。
    • 所以TIntN3

    在引用的表达式中,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 中手动清除了 LineNumberNodes(还有 MacroTools.prettify,它可以为您完成)。

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2013-06-23
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-11-17
      • 1970-01-01
      • 2015-10-01
      相关资源
      最近更新 更多