如何根据Julia中的符号数组操纵变量的值?

时间:2015-07-01 18:53:10

标签: metaprogramming julia

这与David的问题here有些相关。我有兴趣循环遍历符号数组(指向对象)并对循环的每一步执行操作。例如,假设我想编写一个查看一堆变量并将任何标量转换为单元素数组的函数。

widget = "a scalar"
dohickey = ["item 1", "item 2"]
gizmo = "another scalar"

theVariables = [:widget, :dohickey, :gizmo]
for thisVariable in theVariables
    if !(typeof(eval(thisVariable)) <: Array)
        println("Found a scalar")
        #Make it a vector here 
    end
end

理想情况下,最后我们会有以下内容

widget = ["a scalar"]
dohickey = ["item 1", "item 2"]
gizmo = ["another scalar"]

这是一个相当蹩脚的例子,但如何做到这一点?我以为我应该可以使用像

这样的东西
:($thisVariable) = [:($thisVariable)]

但我无法让它发挥作用。

编辑:下面的DSM解决方案适用于上述情况,但在我的实际使用中,我想在一个函数内执行此操作。如果我定义

function getsort(; arga="", argb="", argc="")
    filterSpecs = [:arga, :argb, :argc]
    for ts in filterSpecs
        if !(typeof($ts) <: Array)
            #nothing here
        end
    end
end

然后调用getsort()抛出

error compiling getsort: error compiling __getsort#31__: syntax: prefix $ in non-quoted expression

我显然错过了有关元编程魔法的一些信息。

3 个答案:

答案 0 :(得分:4)

这更像是@ DSM答案的后续内容,但在评论中编写代码很难。需要注意的是:eval在全局范围内进行评估,这会导致奇怪的事情

julia> a = 3
3

julia> function f(a)
         eval(:(a = 1))
         println(a)
       end
f (generic function with 1 method)

julia> f(a)
3

julia> a
1

答案 1 :(得分:3)

从文档的code generation部分,我认为您需要的只是

    @eval $thisVariable = [$thisVariable]

例如:

widget = "a scalar"
dohickey = ["item 1", "item 2"]
gizmo = "another scalar"

theVariables = [:widget, :dohickey, :gizmo]
for thisVariable in theVariables
    if !(typeof(eval(thisVariable)) <: Array)
        println("Found a scalar")
        @eval $thisVariable = [$thisVariable]
    end
end

给了我

Found a scalar
Found a scalar

julia> widget
1-element Array{ASCIIString,1}:
 "a scalar"

julia> dohickey
2-element Array{ASCIIString,1}:
 "item 1"
 "item 2"

julia> gizmo
1-element Array{ASCIIString,1}:
 "another scalar"

答案 2 :(得分:2)

你确定你需要一个宏吗?如果您只想处理功能输入,可以执行以下操作:

julia> function newDictOfArrays(d)
         wrapped=false
         for (k,v) in d
           if !(typeof(v) <: AbstractArray)
             wrapped = true
             d[k] = [v]
           end
         end
         (wrapped, d)
       end
newDictOfArrays (generic function with 1 method)

julia> function f(; kwargs...)
         (wrapped, d) = newDictOfArrays(Dict(kwargs))
         if wrapped
           return f(;d...)
         end
         println("continue knowing all keyword args have been wrapped: $kwargs")
       end
f (generic function with 1 method)

julia> f(a=1, b=[2])
continue knowing all keyword args have been wrapped: Any[(:a,[1]),(:b,[2])]

julia> f(a=[1], b=[2])
continue knowing all keyword args have been wrapped: Any[(:a,[1]),(:b,[2])]

newDictOfArrays检查字典的所有成员以查找不是AbstractArray的子​​类型的值,并使用包装值覆盖该项目。在f中,如果有任何东西被包装,它会再次使用作为关键字参数传递的新字典重新调用相同的函数。没有宏,eval等,尽管你可以考虑编写一个宏,如果经常需要这个宏,会自动将代码注入f。