Почему этот макрос Джулии _не_ требует `esc`?
Я нашел пример unless
Макрос у Юлии здесь записан так:
macro unless(test, branch)
quote
if !$test
$branch
end
end
end
Тем не менее, когда я пытаюсь использовать его, он терпит неудачу (очевидно, есть проблема гигиены, но я не могу понять это точно). Вот тест, который я использовал:
x, y = 0, 1
@unless (x == 5) begin # should execute
y = 3
end
@unless (x == 0) begin # should not execute
y = 5
end
@assert y == 3 # FAILS! SAYS y is 0
Теперь я могу сделать эту работу, обходя только ветку, а не тест:
macro unless(test, branch)
quote
if !$test
$(esc(branch))
end
end
end
Мой вопрос: почему этого достаточно, чтобы избежать только ветки, но не теста? Теперь я попробовал макроэкспандирование. В первом случае без esc
Я получаю это:
julia> macroexpand(:(@unless (x == 5) begin y = 3 end))
quote # none, line 3:
if !(x == 5) # none, line 4:
begin # none, line 1:
#2#y = 3
end
end
end
Теперь, хотя ни один из макропараметров не был экранирован, ТОЛЬКО y
был Генсимед! Кто-нибудь может объяснить, почему это так? (Я знаю, что вторая версия работает, потому что, когда я покидаю ветвь, Y не становится gensymed, а макрос расширяется до y = 3
как и ожидалось. Но я совершенно не понимаю, почему x
не был gensymed, хотя не было никакого смысла esc
.)
1 ответ
Обратитесь к Юлии Док:
Переменные внутри результата макрокоманды классифицируются как локальные или глобальные. Переменная считается локальной, если она назначена (и не объявлена как глобальная), объявлена как локальная или используется в качестве имени аргумента функции. В противном случае он считается глобальным....
Так что в этом случае test
часть ничего не присваивает, поэтому ее переменные считаются глобальными, но в branch
часть, y
таким образом, он считается локальным, и присвоение ему нового значения не изменяется y
в объеме модуля.