Я пытаюсь написать макрос, который оценивает выражение, а затем сравнивает его с несколькими значениями. Я уменьшил проблему до меньшего примера для этого поста.
macro small_bad(item)
quote
$(use_val(esc(item)))
end
end
function use_val(val)
quote
if $val == 1
1
elseif $val == 2
2
else
-1
end
end
end
Поскольку я не хочу оценивать выражение более одного раза, я хочу сохранить его в переменной. Итак, я попробовал это:
macro small_good(item)
quote
begin
val = $(esc(item))
$(begin
use_val(val)
end)
end
end
end
Но затем я понимаю, что val
не определено в интерполяции в @small_good
.
Я также пытался передать use_val(:val)
, но это тоже не удается, потому что система макросов переименует val
во что-то другое.
Как я могу этого добиться?
EDIT: Учитывая первый ответ, я попробовал это в своем реальном коде.
macro match(item, arms)
var = gensym(:var)
quote
let $var = $(esc(item))
$(begin
code = :nothing
for e in reverse(filter((e) -> e isa Expr, arms.args))
code = make_match(var, e, code)
end
code
end)
end
end
end
и получил UndefVarError: ##var#253 not defined
Отказ от ответственности: я знаю, что макрос @match
уже реализован в пакете Match.jl, я повторно реализую его подмножество в качестве учебного упражнения
ИЗМЕНИТЬ 2:
Я понял. После использования предложения Франсуа Февота мне пришлось изменить мою реальную версию use_val
, которая на самом деле выполняла $(esc(val))
вместо $val
.
Ошибка с моей стороны, что я не включил эту деталь. Обновлю суть, чтобы отразить это