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 中我写这个有两个问题:
- 如何将生成的
Expr
对象收集到一个块中? (在 Lisp 中,这是通过将带有 ,@
的列表拼接成 progn
来完成的。)我能想到的最好办法是创建一个 Expr(:block)
,并设置它的 args
到列表中,但这远非优雅。
- 我需要同时使用变量的名称和值。字符串内插和引用表达式都使用
$
,这使问题复杂化,但即使我使用 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
数组更具可读性。
我想编写一个简单的宏来显示变量的名称和值。在 Common Lisp 中,它将是
(defmacro dprint (&rest vars)
`(progn
,@(loop for v in vars
collect `(format t "~a: ~a~%" ',v ,v))))
在 Julia 中我写这个有两个问题:
- 如何将生成的
Expr
对象收集到一个块中? (在 Lisp 中,这是通过将带有,@
的列表拼接成progn
来完成的。)我能想到的最好办法是创建一个Expr(:block)
,并设置它的args
到列表中,但这远非优雅。 - 我需要同时使用变量的名称和值。字符串内插和引用表达式都使用
$
,这使问题复杂化,但即使我使用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
数组更具可读性。