Юлия: Макросы, выражения и Meta.parse - PullRequest
1 голос
/ 24 октября 2019

Все следующие строки кода являются выражениями Julia:

x = 10
1 + 1
println("hi")

Если вы хотите передать выражение в макрос, оно работает следующим образом. Macro foo просто возвращает заданное выражение, которое будет выполнено:

macro foo(ex)
  return ex
end

@foo println("yes") # prints yes

x = @foo 1+1
println(x) # prints 2

Если вы хотите преобразовать строку в выражение, вы можете использовать Meta.parse ():

string = "1+1"
expr = Meta.parse(string)
x = @foo expr
println(x) # prints 1 + 1

Но, очевидно, макрос обрабатывает expr как символ. Что я тут не так делаю?

Заранее спасибо!

1 Ответ

3 голосов
/ 24 октября 2019

Макрос hygiene важен: «макросы должны обеспечивать, чтобы переменные, которые они вводят в возвращаемые выражения, не конфликтовали случайно с существующими переменными в окружающем коде, в который они расширяются». В документах есть раздел. Проще всего показать простой случай:

macro foo(x)
    return :($x)
end

Когда вы вводите обычное выражение в REPL, оно вычисляется немедленно. Чтобы подавить эту оценку, окружите выражение :( ).

julia> 1 + 1
2
julia> :(1 + 1)
:(1 + 1)
# note this is the same result as you get using Meta.parse
julia> Meta.parse("1 + 1")
:(1 + 1)

. Таким образом, Meta.parse преобразует соответствующую строку в выражение. И если вы eval результат, выражение будет оценено. Обратите внимание, что печать простого выражения удаляет внешние :( )

julia> expr = Meta.parse("1 + 1")
:(1 + 1)
julia> print(expr)
1 + 1
julia> result = eval(expr)
2

Обычно макросы используются для манипулирования вещами перед обычной оценкой выражений;в основном это синтаксические преобразования. Макросы выполняются до того, как другой исходный код скомпилирован / оценен / выполнен.

Вместо того, чтобы искать макрос, который оценивает строку, как если бы она была набрана непосредственно в REPL (без кавычек), используйте эту функцию вместо этого.

evalstr(x::AbstractString) = eval(Meta.parse(x))

Хотя я не рекомендую этот следующий макрос, полезно знать технику. Макрос с именем <name>_str используется следующим образом: <name>"<string contents>":

julia> macro eval_str(x)
          :(eval(Meta.parse($x)))
      end

julia> eval"1 + 1"
2

(ps не используйте имена базовых функций в качестве имен переменных, используйте str, а не string)

Пожалуйста, дайте мне знать, если есть что-то, к чему я не обращался.

...