Metaprogramming Julia中的元编程——将整数拼接成变量名

Metaprogramming Julia中的元编程——将整数拼接成变量名,metaprogramming,julia,Metaprogramming,Julia,简短问题: @generated function testfunc(N) :(i_($N)) end testfunc(5) # Desired behavior i_5 ERROR: UndefVarError: i_ not defined in testfunc at none:2 我有一个整数变量N,我想写一个宏来生成一个伪变量I($N) 尝试: @generated function testfunc(N) :(i_($N)) end testfunc(5)

简短问题:

@generated function testfunc(N)
     :(i_($N))
end
testfunc(5) # Desired behavior i_5

ERROR: UndefVarError: i_ not defined
 in testfunc at none:2
我有一个整数变量
N
,我想写一个宏来生成一个伪变量
I($N)

尝试:

@generated function testfunc(N)
     :(i_($N))
end
testfunc(5) # Desired behavior i_5

ERROR: UndefVarError: i_ not defined
 in testfunc at none:2
详细解释:

@generated function testfunc(N)
     :(i_($N))
end
testfunc(5) # Desired behavior i_5

ERROR: UndefVarError: i_ not defined
 in testfunc at none:2
我最近发现了朱莉娅。它有一些生成多维数组索引的虚拟变量的简便技巧

笛卡尔坐标中的
@ntuple
宏可以生成从1开始的序列。例如,
@ntuple5k->i\uk
产生
(i\u1、i\u2、i\u3、i\u4、i\u5)
。在@generated函数中,如果
W=5
,则
@ntuple($W)k->i_k
将生成相同的序列。这不起作用:
@ntuple1k->i_k(k+$W)

我想不出一种仅仅产生的方法,例如,
I_3
如果
N=3
(这可能在@generated函数中)

我的最终目标是使用笛卡尔坐标中的
@nloops
循环一系列虚拟变量,并将结果存储在某个由其中一个虚拟变量索引的存储向量中,例如:

@nloops ($W) i A begin
    # Example generated code for N=2, W=3:
    #    storage[i_2] *= A[i_1, i_2, i_3]
    storage[i_($N)] *= A[(@ntuple ($W) k->i_k)...]
end

我不知道你到底想要什么,但这里有一些提示:

  • @生成的
    参数是宏体中的类型。例如,在
    @生成的函数testfunc(N)
    中,
    N
    类似于
    Int64
    ,而不是
    3

  • 如果您想定义一个变量名,您可能需要通过
    Symbol
    或其他方式来构造它,而不仅仅是引用

  • 例如

    我有一个整数变量N,想写一个宏来生成一个伪变量I($N)

    要直接回答您的问题,您可以通过以下方式完成:-

    i_5 = 7
    
    macro testfunc(expr)
        return symbol(:i_, expr)
    end
    
    @testfunc 5    #This give us back the value of `i_5`, which is 7
    @testfunc(5)   #Another way to write the same macro.
    
    如果我们有一个函数:-

    function foo()
        i_3 = 9
        return @testfunc(3)
    end
    
    foo()
    将为我们提供
    9
    的正确答案

    也就是说,它可能仍然不足以满足您的需要,即将宏放在函数中使用。简而言之,当
    @testfunc(N)
    其中
    N=3
    生成
    i_3
    时,我们希望在函数中引用
    i_3
    ,但如果我们编写:-

    function foo(N)
        i_3 = 9
        return @testfunc(N)
    end
    

    foo(3)
    将给我们一个
    未定义的错误:i\N未定义
    。不确定是否有任何方法来纠正它。我可以想到两种方法来解决这个问题,一种是在全局范围内以脚本形式编写流程,另一种是将整个函数放在引号中。

    正如其他答案所建议的,关键是显式构造所需的符号并将其拼接到生成的表达式中。还请注意,您可以使用简化
    A[i_1,i_2,…]
    表达式

    根据我的经验,学习如何使用这些宏的最佳方法是使用
    macroexpand

    julia> using Base.Cartesian
           W = 3
           N = 2
           macroexpand(:(@nloops ($W) i A begin
                             storage[$(symbol(:i_, N))] *= @nref $W A i
                         end))
    quote  # cartesian.jl, line 31:
        for i_3 = 1:size(A,3) # cartesian.jl, line 32:
            nothing # cartesian.jl, line 33:
            begin  # cartesian.jl, line 31:
                for i_2 = 1:size(A,2) # cartesian.jl, line 32:
                    nothing # cartesian.jl, line 33:
                    begin  # cartesian.jl, line 31:
                        for i_1 = 1:size(A,1) # cartesian.jl, line 32:
                            nothing # cartesian.jl, line 33:
                            begin  # none, line 5:
                                storage[i_2] *= A[i_1,i_2,i_3]
                            end # cartesian.jl, line 34:
                            nothing
                        end
                    end # cartesian.jl, line 34:
                    nothing
                end
            end # cartesian.jl, line 34:
            nothing
        end
    end