Julia 中的 Quote-unquote 习语和连接 Expr 对象

Quote-unquote idiom in Julia & concatenating Expr objects

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

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

在 Julia 中我写这个有两个问题:

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

@show 宏已经存在。能够自己实现它很有帮助,所以以后你可以做其他喜欢的事情,比如制作一个可以显示数组大小的东西..

对于您的特定变体: 答案是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

oxinabox 的回答很好,但我应该提到 ,@x 的等价物是 $(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

我个人认为这比推送到 .args 数组更具可读性。