【问题标题】:Quote-unquote idiom in Julia & concatenating Expr objectsJulia 中的 Quote-unquote 习语和连接 Expr 对象
【发布时间】:2017-02-17 06:31:19
【问题描述】:

我想编写一个简单的宏来显示变量的名称和值。在 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) 与@987654330 不一样@ 在 CL 中...

我当前的宏是这样的:

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 的效果。再次感谢!

【问题讨论】:

    标签: macros metaprogramming julia


    【解决方案1】:

    @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
    

    【讨论】:

    • 谢谢!有没有更优雅的方式来创建一个块? (我的问题的第一部分)
    • 回答我的问题,查看 julia/base/show.jl,他们使用相同的方法,除了他们 push! 递增到 ex.args,所以在 Julia 中这必须是惯用的方式去做。
    • Expr(:block)quote end 是等价的,但quote end 将保留行号信息。
    • 普通lisp中quote的等价物是QuoteNode,而不是Meta.quot。但是,区别非常细微,通常并不重要。
    • @vukung: 可以选择:macro dprint(vars...) Expr(:block ,(:(println($(Meta.quot(v)), " = ", $v)) for v in vars)...) end 真的好不好。
    【解决方案2】:

    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 数组更具可读性。

    【讨论】:

    • 谢谢!是的,这回答了第一部分。
    猜你喜欢
    • 2020-12-18
    • 2012-04-15
    • 1970-01-01
    • 1970-01-01
    • 2020-06-28
    • 1970-01-01
    • 2017-01-19
    • 2016-06-13
    • 1970-01-01
    相关资源
    最近更新 更多