Короче говоря, вам не хватает понятия макро-гигиены и, в частности, функции esc
.
Хотя эта часть документации является хорошее чтение для тех, кто хочет разрабатывать свои собственные макросы, давайте попробуем немного рассказать о том, что делает гигиена макросов в этом конкретном примере, и как вы можете что-то исправить.
Полезный способ отладки макросов предоставляется @macroexpand
:
julia> @macroexpand @dbg "initialization" begin
foo = rand(10)
println("foo = ", foo)
end
quote
#= REPL[1]:3 =#
var"#32#title" = "initialization"
#= REPL[1]:4 =#
Main.println("Entering $(var"#32#title")")
#= REPL[1]:5 =#
begin
#= REPL[5]:2 =#
var"#33#foo" = Main.rand(10)
#= REPL[5]:3 =#
Main.println("foo = ", var"#33#foo")
end
#= REPL[1]:6 =#
Main.println("Leaving $(var"#32#title")")
end
Оставляя в стороне все комментарии в пределах маркеров #= ... =#
, мы видим почти тот код, который хотели получить: блок кода пользователя был окружен инструкциями, печатающими " Вход "и" уход "уведомления. Однако есть одно заметное отличие: имена переменных, такие как foo
или title
, были заменены на странно выглядящие имена, такие как var"#33#foo"
или var"#32#title"
. Это то, что называется « макро-гигиена », и это помогает избежать конфликтов, которые могут возникнуть между переменными, используемыми в самом макросе (например, title
в этом примере), и переменными, используемыми в блоке кода. предоставляется в качестве аргумента макроса (например, foo
здесь). (Например, подумайте, что бы произошло, если бы вы использовали @dbg
в блоке кода, который определяет переменную title
.)
Джулия ошибается, и таким образом защищает все переменные, появляющиеся в макрос. Если вы хотите отключить это для выбранных частей выражения, созданного макросом, вы можете заключить эти подвыражения в функцию esc
. В вашем примере вы должны, например, экранировать предоставленное пользователем выражение:
macro dbg(block_title, expr)
quote
title = $block_title
println("Entering $title")
$(esc(expr))
println("Leaving $title")
end
end
Теперь все должно работать так, как вы хотите:
julia> @dbg "initialization" begin
foo = rand(10)
println("foo = ", foo)
end
Entering initialization
foo = [0.2955287439482881, 0.8989053281359838, 0.27751430906108343, 0.4920810199867245, 0.7633806735297282, 0.34535540650110597, 0.7099231627594489, 0.39978144801175564, 0.9104888704503833, 0.1983996781283539]
Leaving initialization
julia> @dbg "computation" begin
foo .+= 1
end
Entering computation
Leaving computation
julia> foo
10-element Array{Float64,1}:
1.295528743948288
1.8989053281359838
1.2775143090610834
1.4920810199867245
1.7633806735297282
1.345355406501106
1.709923162759449
1.3997814480117556
1.9104888704503833
1.198399678128354