本文介绍了Julia宏,用于将f(dim1,dim2,..)= value转换为f(value,dim1,dim2,..)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

限时删除!!

我正在尝试编写一个Julia宏来对此进行转换:

I am trying to write a Julia macro that transforms this:

[par1!( par2(d1,d2)+par3(d1,d2)   ,d1,d2,dfix3) for d1 in DIM1, d2 in DIM2]

(不是很启发)到更具可读性的内容中,例如:

(not very inspiring) into something much more readable, like this:

@meq par1!(d1 in DIM1, d2 in DIM2, dfix3) =  par2(d1,d2)+par3(d1,d2)

其中par1!()是用于设置某些多维数据的函数,而par2()是类型为getData()的函数.

where par1!() is a function to set some multi-dimensional data and par2() is a getData()-type of function.

我正在尝试使用宏来实现它,但是当我第一次接触julia marcro时,我不确定如何从各个部分中组装"最终表达.这是我到目前为止所做的:

I am trying to implement it using a macro, but as I am on my first experience with julia marcro, I'm not sure how to "assemble" the final expression from the various pieces..Here is what I done so far:

macro meq(eq)
   # dump(eq)
    lhs_par               = eq.args[1].args[1]
    rhs                   = eq.args[2]
    lhs_dims              = eq.args[1].args[2:end]
    loop_counters         = [d.args[2] for d in lhs_dims if typeof(d) == Expr]
    loop_sets             = [d.args[3] for d in lhs_dims if typeof(d) == Expr]
    loop_wholeElements    = [d for d in lhs_dims if typeof(d) == Expr]
    lhs_dims_placeholders = []
    for d in lhs_dims
        if typeof(d) == Expr
            push!(lhs_dims_placeholders,d.args[2])
        else
            push!(lhs_dims_placeholders,d)
        end
    end
    outExp =  quote
      [$(lhs_par)($(rhs),$(lhs_dims_placeholders ...)) for  $(loop_wholeElements ...) ]
    end
    #show(outExp)
    return outExp
end

但是,由于for $(loop_wholeElements)部分,上述宏无法编译并返回语法错误(无效的迭代规范")……的确,我不知道如何处理lhs_dims_placeholders和loop_wholeElements中的表达式,以便组装"扩展的表达式…

However the above macro doesn't compile and returns a syntax error ("invalid iteration specification") due to the for $(loop_wholeElements) part… indeed I don’t know how to treat the expressions in lhs_dims_placeholders and loop_wholeElements in order to "assemble" the expanded expression…

发布的带有d1d2dfix3的示例仅是一种特定情况,但是该宏应该能够处理任何循环的尺寸.我认为上面的宏可以做到这一点,但是我不知道如何构建最终表达式..:-(

The example posted, with d1, d2 and dfix3, is only a specific case, but the macro should be able to handle whichever dimensions are looped for..I think the macro up there does that, but I don't know how to build the final expression.. :-(

推荐答案

我们可以手动使用 MacroTools.jl 作为用于模板匹配的便捷工具:

Instead of manually doing those hard-coded args matching stuff, we could use MacroTools.jl as a handy tool for template matching:

julia> using MacroTools

julia> macro meq(ex)
           @capture(ex, f_(d1_ in dim1_, d2_ in dim2_, dfix3_) = body__)
           ret = :([$f($(body[]), $d1, $d2, $dfix3) for $d1 in $dim1, $d2 in $dim2])
       end
@meq (macro with 1 method)

julia> prettify(@macroexpand @meq par1!(d1 in DIM1, d2 in DIM2, dfix3) =  par2(d1,d2)+par3(d1,d2))
:([(Main.par1!)((Main.par2)(lobster, redpanda) + (Main.par3)(lobster, redpanda), lobster, redpanda, Main.dfix3) for lobster = Main.DIM1, redpanda = Main.DIM2])


更新:

所需的最终表达式是comprehension,似乎出于某种原因,Julia无法弄清楚for expr(其中$expr #=> XXX in XXX)是一种理解.解决方法是直接使用其简化形式:


UPDATE:

The desired final expression is a comprehension, it seems that for some reason Julia couldn't figure out for expr(where $expr #=> XXX in XXX) is a comprehension. The workaround is directly using its lowered form:

julia> using MacroTools

julia> par1(a, b, c, d) = a + b + c + d
par1 (generic function with 1 method)

julia> par2(a, b) = a + b
par2 (generic function with 1 method)

julia> macro meq(ex)
           @capture(ex, par_(dims__) = rhs_)
           loopElements = []
           dimsPlaceholders = []
           for d in dims
               @capture(d, di_ in DIMi_) || (push!(dimsPlaceholders, d); continue)
               # push!(loopElements, x)
               push!(loopElements, :($di = $DIMi))
               push!(dimsPlaceholders, di)
           end
           ret = Expr(:comprehension, :($par($(rhs),$(dimsPlaceholders...))), loopElements...)
       end
@meq (macro with 1 method)

julia> prettify(@macroexpand @meq par1!(d1 in DIM1, d2 in DIM2, dfix3) =  par2(d1,d2)+par3(d1,d2))
:($(Expr(:comprehension, :((Main.par1!)(begin
            (Main.par2)(bee, wildebeest) + (Main.par3)(bee, wildebeest)
        end, bee, wildebeest, Main.dfix3)), :(bee = Main.DIM1), :(wildebeest = Main.DIM2))))

julia> @meq par1(m in 1:2, n in 4:5, 3) =  par2(m,n) + par2(m,n)
2×2 Array{Int64,2}:
 18  21
 21  24

请注意,如果我们使用push!(loopElements, x)而不是push!(loopElements, :($di = $DIMi)),则在生成的表达式中d1,d2的变量范围将是错误的.让我们等待有经验的人给出详尽的解释.

Note that, the variable scope of d1,d2 in generated expression will be wrong if we use push!(loopElements, x) rather than push!(loopElements, :($di = $DIMi)). Let's wait for someone knowledgeable to give a thorough explanation.

这篇关于Julia宏,用于将f(dim1,dim2,..)= value转换为f(value,dim1,dim2,..)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

1403页,肝出来的..

09-06 15:05