Локальная переменная Julia не определена в выражении eval - PullRequest
3 голосов
/ 07 февраля 2020

Учитывая следующую функцию,

function floop(exp)
    a = 5
    b = 10
    ex = Expr(:call, :+, 1, exp);
    return eval(ex);
end

, если я затем запускаю

floop(Symbol("b"))

Я получаю сообщение об ошибке, говорящее, что b не определено. Почему это не работает? Как я могу сделать эту работу?

Ответы [ 2 ]

3 голосов
/ 07 февраля 2020

Одной из ключевых вещей, которые позволяют Джулии быть быстрой, является то, что eval всегда работает в глобальном масштабе. Это означает, что он никогда не может ссылаться на локальные переменные.

1 голос
/ 07 февраля 2020

Вы можете сделать что-то вроде следующего макроса, выбирая значение во время раскрытия, в зависимости от статически известного Symbol:

julia> macro floop(selector::QuoteNode)
           choices = Dict(:a => 5, :b => 10)
           ex = :(1 + $(choices[selector.value]))
           return ex
       end
@floop (macro with 1 method)

julia> @macroexpand @floop(:a)
:(1 + 5)

julia> @macroexpand @floop(:b)
:(1 + 10)

julia> @floop(:c)
ERROR: LoadError: KeyError: key :c not found
Stacktrace:
 [1] getindex(::Dict{Symbol,Int64}, ::Symbol) at ./dict.jl:477
 [2] @floop(::LineNumberNode, ::Module, ::QuoteNode) at ./REPL[27]:3
in expression starting at REPL[33]:1

julia> s = :a; @floop(s)
ERROR: LoadError: MethodError: no method matching @floop(::LineNumberNode, ::Module, ::Symbol)
Closest candidates are:
  @floop(::LineNumberNode, ::Module, ::QuoteNode) at REPL[1]:2
in expression starting at REPL[2]:1

Вам решать, как на самом деле хранить фактические значения. Глобальный словарь const может быть опцией или просто цепочкой if.

(в действительности могут быть иные вещи, чем Symbol в QuoteNode, но их трудно соединить в вызов макроса, и они также просто подняли бы KeyError, поэтому я не включил дополнительную обработку этого.)

...