Julia 朱莉娅:把字符串传给宏

Julia 朱莉娅:把字符串传给宏,julia,Julia,假设我有一个宏定义为: macro foomacro(ex::Expr) dump(ex) ex end 目前,我希望以解析字符串的形式传递表达式,以便传递通过字符串串联获得的相当复杂且大小写相关的表达式 然而,尝试: @foomacro 1+2+3 给出了预期的结果6 @foomacro parse("1+2+3") 返回解析后的表达式:(1+2+3),而不是实际解析它 据我所知,这两个宏应该接收相同的表达式,但显然不是这样 我如何让这个MWE工作 ps:我想出了这个解决

假设我有一个宏定义为:

macro foomacro(ex::Expr)
    dump(ex)
    ex
end
目前,我希望以解析字符串的形式传递表达式,以便传递通过字符串串联获得的相当复杂且大小写相关的表达式

然而,尝试:

@foomacro 1+2+3
给出了预期的结果6

@foomacro parse("1+2+3")
返回解析后的表达式:(1+2+3),而不是实际解析它

据我所知,这两个宏应该接收相同的表达式,但显然不是这样

我如何让这个MWE工作

ps:我想出了这个解决方案,但我觉得它非常脏而且“不正确”


ps:如果这是相关的,那么目前代码运行在0.6.4上,如果可能的话,我宁愿不更新到1.0,因为这会将我的实际项目推迟到很多…

你把级别弄混了。为了清晰起见,让我们引入一个中间函数:

function foomacro_impl(expr)
    dump(expr)
    expr
end

macro foomacro(expr)
    foomacro_impl(expr)
end
如果运行,将解析表达式
@foomacro
,将
部分传递到
foomacro\u impl
,并将结果视为表达式并插入,而不是原始表达式。这意味着编写
@foomacro 1+2+3
相当于编写

let expr = :(1+2+3)
    dump(expr)
    expr
end
返回

Expr
  head: Symbol call
  args: Array{Any}((4,))
    1: Symbol +
    2: Int64 1
    3: Int64 2
    4: Int64 3
:(1 + 2 + 3)
计算结果为6的
Expr

另一方面,在
@foomacro Meta.parse(“1+2+3”)
中,整个参数
parse(“1+2+3”)
用作
expr

julia> let expr = :(Meta.parse("1+2+3"))
           dump(expr)
           expr
       end
Expr
  head: Symbol call
  args: Array{Any}((2,))
    1: Expr
      head: Symbol .
      args: Array{Any}((2,))
        1: Symbol Meta
        2: QuoteNode
          value: Symbol parse
    2: String "1+2+3"
:(Meta.parse("1+2+3"))
因此,宏调用的结果是表达式
Meta.parse(“1+2+3”)
,它的计算结果是另一个表达式
:(1+2+3)
,因为它是对
parse
的调用。因此,这两种形式没有得到相同的表达

但是有一些方法可以手动解析表达式并将其传递给宏:

  • 您可以像我一样,使用单独的“宏实现函数”。然后,
    @foomacro bla
    返回的表达式等价于
    foomacro_impl(Meta.parse(bla))
    。(顺便说一句,这种方法对于测试非常有用,我大多数时候都推荐它。)
  • 可以使用宏
    @eval
    构造表达式,拼接到其中,然后立即对其求值:

    julia> @eval @foomacro $(Meta.parse("1+2+3"))
    Expr
      head: Symbol call
      args: Array{Any}((4,))
    1: Symbol +
        2: Int64 1
        3: Int64 2
        4: Int64 3
    6
    
    (或者类似地,使用
    eval
    和手动构造的
    Expr
    值。)


  • 你把层次搞混了。为了清晰起见,让我们引入一个中间函数:

    function foomacro_impl(expr)
        dump(expr)
        expr
    end
    
    macro foomacro(expr)
        foomacro_impl(expr)
    end
    
    如果运行,将解析表达式
    @foomacro
    ,将
    部分传递到
    foomacro\u impl
    ,并将结果视为表达式并插入,而不是原始表达式。这意味着编写
    @foomacro 1+2+3
    相当于编写

    let expr = :(1+2+3)
        dump(expr)
        expr
    end
    
    返回

    Expr
      head: Symbol call
      args: Array{Any}((4,))
        1: Symbol +
        2: Int64 1
        3: Int64 2
        4: Int64 3
    :(1 + 2 + 3)
    
    计算结果为6的
    Expr

    另一方面,在
    @foomacro Meta.parse(“1+2+3”)
    中,整个参数
    parse(“1+2+3”)
    用作
    expr

    julia> let expr = :(Meta.parse("1+2+3"))
               dump(expr)
               expr
           end
    Expr
      head: Symbol call
      args: Array{Any}((2,))
        1: Expr
          head: Symbol .
          args: Array{Any}((2,))
            1: Symbol Meta
            2: QuoteNode
              value: Symbol parse
        2: String "1+2+3"
    :(Meta.parse("1+2+3"))
    
    因此,宏调用的结果是表达式
    Meta.parse(“1+2+3”)
    ,它的计算结果是另一个表达式
    :(1+2+3)
    ,因为它是对
    parse
    的调用。因此,这两种形式没有得到相同的表达

    但是有一些方法可以手动解析表达式并将其传递给宏:

  • 您可以像我一样,使用单独的“宏实现函数”。然后,
    @foomacro bla
    返回的表达式等价于
    foomacro_impl(Meta.parse(bla))
    。(顺便说一句,这种方法对于测试非常有用,我大多数时候都推荐它。)
  • 可以使用宏
    @eval
    构造表达式,拼接到其中,然后立即对其求值:

    julia> @eval @foomacro $(Meta.parse("1+2+3"))
    Expr
      head: Symbol call
      args: Array{Any}((4,))
    1: Symbol +
        2: Int64 1
        3: Int64 2
        4: Int64 3
    6
    
    (或者类似地,使用
    eval
    和手动构造的
    Expr
    值。)


  • 也许你想
    eval(解析(“1+2+3”))
    ?不,我试过了,它在这种情况下有效(因为宏传递6,因此返回6),但它在我的非MWE中不起作用,因为宏实际上是在做事情。也许你想
    eval(解析(“1+2+3”)
    ?不,我试过了,它在这种情况下有效(因为宏被传递6,因此返回6)但它在我的非MWE中不起作用,因为宏实际上是执行操作的。非常感谢您的深入回答,但是当我尝试todo=“1+2+3”然后尝试ATeval ATfoomacro$(Meta.parse(todo))时,这两种方法似乎都失败了使用
    foo_impl
    可能需要在它之后额外调用
    eval
    ,因为它只返回宏将构造的表达式。另一个变体对我来说很有用。不过,有一件事是,Julia 1.0中需要
    Meta.parse
    ,而在旧版本中只是
    parse
    ——我不知道这是否可以使用任何问题…事实上,我应该计算结果表达式,但这会返回一个错误,即使foo_impl生成的表达式和宏相同,但宏的计算方式不同,这可能吗?您的解决方案在我的特定情况下无法工作,但这很可能与whic的基础函数有关h我无法提供MWE。但是,答案确实回答了与MWE相关的问题,因此我会接受其他遇到相同问题的人的答案:)嗯。您可以尝试使用调试您的问题,以查看调用结果。非常感谢您的深入回答,但是当我尝试todo=“1+2+3”,然后是ATeval ATfoomacro$(Meta.parse(todo))使用
    foo_impl
    可能需要在它之后额外调用
    eval
    ,因为它只返回宏将构造的表达式。另一个变体对我来说很有用。不过,有一件事是,Julia 1.0中需要
    Meta.parse
    ,而在旧版本中只是
    parse
    ——我不知道这是否可以使用任何问题…事实上,我应该计算结果表达式,但这会返回一个错误,即使foo_impl生成的表达式和宏在某种程度上是相同的