#metaprogramming #julia
#метапрограммирование #джулия
Вопрос:
Я пытаюсь определить макрос для шаблона функции, то есть шаблон, в который вы можете легко вставить соответствующий код, но не хотите раскрывать пользователю все подробные детали реализации. Например, я хотел бы что-то вроде этого, которое переносит выражение в более сложную функцию:
macro make_complex_function(ex)
quote
function (alg,f,t,u,k)
# Add some stuff on top
condition1 = false
condition2 = false
#...
#Put in the user's code
$(esc(ex))
# Put a footer
return some,stuff,here,long,annoying,list
end
end
end
таким образом, пользователь может легко вставлять небольшие фрагменты логики (с помощью упрощенного API / документации):
easy_func = @make_complex_function begin
if u > 1
print("oh no! It happened!")
end
end
в то время как полная мощность по-прежнему доступна для более продвинутых пользователей. Однако, если вы запустите этот код, вы получите доступ к неопределенным ссылочным ошибкам. Я думаю, это потому, что я неправильно экранирую выражение и должен каким-то образом экранировать всю функцию, но не уверен, как.
Ответ №1:
краткий ответ: не используйте esc
и не размещайте его во всем quote
блоке.
julia> macro m(e)
quote
function f(x)
return $(e)
end
end
end
@m (macro with 1 method)
julia> f = @m x 1
#1#f (generic function with 1 method)
julia> f(2)
3
julia> macro m(e)
esc(quote
function f(x)
return $(e)
end
end)
end
@m (macro with 1 method)
julia> f = @m x 1
f (generic function with 1 method)
julia> f(2)
3
длинный ответ:
- кое-что о гигиене
julia добавит префикс к любым именам, определенным внутри макроса, делая их недоступными где-либо еще. esc
отменит эти префиксы, чтобы имена в конечном выражении были точными, что вы пишете. Поэтому помните, что используйте только esc
в том случае, если вам нужно получить доступ к этим переменным вне макроса, что не относится к вашему примеру.
- используется
macroexpand
для помощи в создании макросов
например, если вы разместили esc
не в том месте, как показано ниже:
macro m(e)
quote
function f(x)
return $(esc(e))
end
end
end
вы получите такое выражение:
julia> macroexpand( :( @m x 1 ) )
quote # REPL[9], line 3:
function #1#f(#2#x) # REPL[9], line 4:
return x 1
end
end
Вы можете обнаружить, что аргумент f
и его аргумент имеют префикс специальной вещи (поскольку они не экранируются), в то время как тело просто x
, которое нигде не определено.
- лучше использовать функции, а не макросы
Как правило, лучше использовать функции более высокого порядка для реализации «шаблонов функций», поскольку они легче читаются и могут использовать современные инструменты статического анализа — хотя, похоже, у Джулии их еще не было :). Запись сигнатур функций и их передача кажутся раздражающими, но они того стоят.
Комментарии:
1. «Запись сигнатур функций и их передача кажутся раздражающими, но они того стоят». Как всегда, зависит от того, что вы делаете.