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