4

次の関数を検討してください。

function func(vars::Dict{Symbol, Any})

end

のスコープにローカル変数を作成したいのですが、func変数名はそれぞれ のキーでありvars、変数の値はvars指定されたキーに対応する の値です。

私はeval()次のようなもので使用できることを認識しています:

for (k, v) in vars
    eval(:($k = $v))
end

ただし、これはグローバル スコープで変数を定義するため、パフォーマンスに影響があり、既存のグローバル変数をオーバーライドする可能性があります。

PS私が行っているアプローチとは大幅に異なる提案がある場合に備えて、コンテキストを追加します. ユーザーが任意の制約式を使用して最適化モデルを動的に作成できるように、 JuMPの周りにラッパーを実装しています。制約式はシンボルを使用してJuMP定義されており、それらのシンボルは現在のスコープで定義する必要があるため、ユーザーはそれらのシンボルとその値をディクショナリで関数に提供する必要があります。シンボルをグローバルに定義するのは面倒です。ユーザーは理想的には、同じ制約式 (つまり、同じシンボル) で異なる値を使用して関数を複数回実行できる必要があるためです。

4

1 に答える 1

2

注:私はメタプログラミングの専門家ではありません。

ジェネリック関数ではなく、代わりにマクロまたは生成された関数を使用して、このようなことができると思います。

これに基づいて:

julia> macro bar(dict)
           dump(dict, 10)
       end

julia> @bar Dict(:foo => "foo", :bar => "bar", :baz => "baz");
Expr 
  head: Symbol call
  args: Array(Any,(4,))
    1: Symbol Dict
    2: Expr 
      head: Symbol =>
      args: Array(Any,(2,))
        1: Expr 
          head: Symbol quote
          args: Array(Any,(1,))
            1: Symbol foo
          typ: Any
        2: ASCIIString "foo"
      typ: Any
    3: Expr 
      head: Symbol =>
      args: Array(Any,(2,))
        1: Expr 
          head: Symbol quote
          args: Array(Any,(1,))
            1: Symbol bar
          typ: Any
        2: ASCIIString "bar"
      typ: Any
    4: Expr
      head: Symbol =>
      args: Array(Any,(2,))
        1: Expr
          head: Symbol quote
          args: Array(Any,(1,))
            1: Symbol baz
          typ: Any
        2: ASCIIString "baz"
      typ: Any
  typ: Any

私はこのようなことをすることができました。それはより多くのエラーチェックを行うことができ、また汎用マクロは開発ブランチでこれを (少なくともエラーチェックのために) 簡単にします:

julia> macro foo(dict)
           blk = Expr(:block)
           if dict.head == :call && dict.args[1] == :Dict
               for arg in dict.args[2:end]
                   sym = arg.args[1].args[1]
                   val = arg.args[2]
                   push!(blk.args, esc(:($sym = $val)))
               end
           else
               error("Need a Dict{Symbol, Any}")
           end
           blk
       end

julia> @foo Dict(:foo => "foo", :bar => "bar", :baz => "baz");

julia> @show foo bar baz;
foo = "foo"
bar = "bar"
baz = "baz"

julia> let    # local scope
           @foo Dict(:foo => "foo", :bar => "bar", :baz => "baz")
           @show foo bar baz
       end;
foo = "foo"
bar = "bar"
baz = "baz"

dict 変数を作成して@fooマクロに渡すことはできないことに注意してください (ここでも、一般的なマクロSymbolを使用すると、エラーをディスパッチするメソッドが存在する可能性があるため、これが簡単になりますか?):

julia> dict = Dict(:foo => "foo", :bar => "bar", :baz => "baz");

julia> @foo dict
ERROR: type Symbol has no field head

この時点で次のようになります。

@foo a 1 b 2 c 3

また

@foo :a=>1 :b=>2 :c=>3

私見の方がいいでしょう。

これが最適ではない理由を誰かが説明してくれたら、とてもありがたいです! この回答はコメントである必要がありましたが、コードが多すぎます。

一般的なマクロと生成された関数で同様のものを実装して、投稿を更新しようとします。

于 2016-01-28T16:02:33.777 に答える