Julia& amp;中引用不引用的成语连接Expr对象

时间:2016-10-08 10:05:55

标签: macros metaprogramming julia

我想写一个简单的宏,显示名称&变量的值。在Common Lisp中,它将是

(defmacro dprint (&rest vars)
  `(progn
    ,@(loop for v in vars
            collect `(format t "~a: ~a~%" ',v ,v))))

在朱莉娅,我写了两个问题:

  1. 如何将生成的Expr个对象收集到块中? (在Lisp中,这是通过将列表与,@拼接到progn来完成的。)我能想到的最好的方法是创建Expr(:block)并设置其args列表,但这远非优雅。
  2. 我需要同时使用变量的名称和值。字符串内部的插值和引用的表达式都使用$,这会使问题复杂化,但即使我使用string进行连接,我也无法打印变量的名称 - 至少:($v)不会与CL ... {/ li>中的',v相同

    我当前的宏看起来像这样:

    macro dprint(vars...)
      ex = Expr(:block)
      ex.args = [:(println(string(:($v), " = ", $v))) for v in vars]
      ex
    end
    

    观察宏观扩展显示了问题:

    julia> macroexpand(:(@dprint x y))
    quote 
        println(string(v," = ",x))
        println(string(v," = ",y))
    end
    

    我想得到

    quote 
        println(string(:x," = ",x))
        println(string(:y," = ",y))
    end
    

    任何提示?

    编辑:结合答案,解决方案似乎如下:

    macro dprint(vars...)
      quote
        $([:(println(string($(Meta.quot(v)), " = ", $v))) for v in vars]...)
      end
    end
    

    ...即$(Meta.quot(v))使用',v$(expr...)使用,@expr。再次感谢你!

2 个答案:

答案 0 :(得分:7)

@show宏已存在。能够自己实现它是有帮助的,所以稍后你可以做其他的喜欢,比如make会显示一个数组的大小。

对于您的特定变体: 答案是Meta.quot

macro dprint(vars...)
     ex = Expr(:block)
     ex.args = [:(println($(Meta.quot(v)), " = ", $v)) for v in vars]
     ex
end

见:

julia> a=2; b=3;

julia> @dprint a
a = 2

julia> @dprint a b
a = 2
b = 3

答案 1 :(得分:3)

oxinabox的答案很好,但是我应该提到相当于,@x的{​​{1}}(这是你问题的另一部分)。

例如,考虑宏

$(x...)

和调用

macro _begin(); esc(:begin); end

macro @_begin()(args...)
    quote
        $(args...)
    end |> esc
end

(虽然可疑可读)产生预期结果@begin x=1 y=2 x*y 。 (2宏不是示例的一部分;但它是必需的,因为@_begin是保留字,因此需要宏来直接访问该符号。)

请注意

begin

我认为这比推送到julia> macroexpand(:(@begin 1 2 3)) quote # REPL[1], line 5: 1 2 3 end 数组更具可读性。