这个朱莉娅交换出了什么问题!宏?

时间:2014-09-07 01:03:17

标签: macros julia

我正在尝试在Julia中编写一个简单的swap!宏来理解宏系统。到目前为止,这是我的代码:

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

我做错了什么?

4 个答案:

答案 0 :(得分:7)

我想你可能想要类似下面的东西,但却被hygiene搞砸了。诀窍是正确逃脱。

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,但在其他2个语句中没有,因此设置引入变量的值而不是预期的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

答案 1 :(得分:1)

我从来没有听说过朱莉娅,但由于它的名字很酷,我突然出现了。交换的经过验证的真实模式是:

swap(a, b)
    tmp <- a
    a <- b
    b <- tmp

您的代码看起来像这样(除非我不理解Julia,在这种情况下,我会乐意删除此答案)...

swap(a, b)
    tmp <- b
    a <- b
    b <- tmp

记录b的值,然后通过在其上写b来丢失a的值,然后将b设置为存储在tmp中的原始值。

答案 2 :(得分:1)

根据这篇文章https://rosettacode.org/wiki/Generic_swap,似乎朱莉娅不需要任何临时变量。

a, b = b, a

所以,我们可以更容易地写它。

答案 3 :(得分:-1)

虽然接受的答案工作得很好,但我认为临时变量的使用可能会遗漏在宏的一些概念上。我会这样写的......

macro swap!(x,y)
  quote
    $(esc(x)) = $(eval(y))
    $(esc(y)) = $(eval(x))
    return
  end
end

然后

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

由于宏返回一个将在运行时计算的字符串/表达式,您也可以跳过临时变量并将所需的值直接放入返回的字符串中。