Macros 什么';茱莉亚交换错了!宏?
我正在尝试编写一个简单的Macros 什么';茱莉亚交换错了!宏?,macros,julia,Macros,Julia,我正在尝试编写一个简单的交换宏,了解宏系统。以下是我目前的代码: macro swap!(x, y) quote local tmp = $(esc(y)) $x = $(esc(y)) $y = tmp end end a = 1 b = 2 @swap!(a, b) # prints: a: 1, b: 2 println("a: $a, b: $b") 这运行时不会出错,但实际上不会更改值。Julia似乎没有一个只扩展
交换宏,了解宏系统。以下是我目前的代码:
macro swap!(x, y)
quote
local tmp = $(esc(y))
$x = $(esc(y))
$y = tmp
end
end
a = 1
b = 2
@swap!(a, b)
# prints: a: 1, b: 2
println("a: $a, b: $b")
这运行时不会出错,但实际上不会更改值。Julia似乎没有一个只扩展宏而不执行宏的函数(据我所见),所以这很难调试
REPL中的等效报价似乎与预期一样有效:
julia> a = 1
1
julia> a_sym = :a
:a
julia> a_sym
:a
julia> b = 2
2
julia> b_sym = :b
:b
julia> eval(quote
tmp = $a_sym
$a_sym = $b
$b_sym = tmp
end)
1
julia> a
2
julia> b
1
我做错了什么?我从来没有听说过朱莉娅,但因为这个名字听起来很酷,我突然出现了。经过验证的交换模式是:
swap(a, b)
tmp <- a
a <- b
b <- tmp
交换(a、b)
tmp我想你可能想要下面这样的东西,但却被它搞砸了。诀窍是正确地逃脱
macro swap(x,y)
quote
local tmp = $(esc(x))
$(esc(x)) = $(esc(y))
$(esc(y)) = tmp
end
end
下面是它的外观
julia> macroexpand(quote @swap(x,y) end)
quote # none, line 1:
begin # none, line 3:
local #189#tmp = x # line 4:
x = y # line 5:
y = #189#tmp
end
end
效果
julia> x
1
julia> y
2
julia> @swap(x,y)
julia> x
2
julia> y
1
相比之下,宏在一个赋值中正确地转义了y,但在其他两个语句中没有,因此设置了引入变量的值,而不是预期的x和y
julia> macroexpand(quote @swap!(x,y) end)
quote # none, line 1:
begin # none, line 3:
local #208#tmp = y # line 4:
#209#x = y # line 5:
#210#y = #208#tmp
end
end
虽然公认的答案很好,但我认为temp变量的使用可能遗漏了宏的一些概念功能。我会这样写
macro swap!(x,y)
quote
$(esc(x)) = $(eval(y))
$(esc(y)) = $(eval(x))
return
end
end
然后
由于宏返回一个将在运行时进行计算的字符串/表达式,您不妨跳过temp变量,将所需的值直接放入返回的字符串中。根据本文,Julia似乎不需要任何临时变量
a, b = b, a
因此,我们可以更轻松地编写它。啊哈,很好!这还不足以修复它,但这肯定是代码的问题。你确定a,b=b,a
赋值还不够吗?@juliom这当然有效,但我的目的是学习Julia宏。Julia确实有macroexpand。不过,给它打电话有点棘手<代码>宏扩展(:(@swap x,y))
只在全局范围内工作。您通常不想使用eval
,尤其是在宏中。我今天早上才知道宏,你的评论让我消除了许多误解。感谢您指出这一点。另请参阅宏中引用的return语句。我编辑了答案,以从宏中删除return
语句。这是不必要的,也是错误的。它不是从宏返回,而是将返回语句拼接到使用宏的任何上下文中!这意味着如果您在函数中使用了它,那么该函数将在@swap
之后立即返回!begin块的值只是其最后一个表达式的值。
julia> test1 = 1
1
julia> test2 = 2
2
julia> macroexpand(:(@swap! test1 test2))
quote # none, line 3:
test1 = 2 # line 4:
test2 = 1 # line 5:
return
end
a, b = b, a