Почему этот макрос Джулии _не_ требует `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 в объеме модуля.

Другие вопросы по тегам