【问题标题】:Julia: Macros, Expressions and Meta.parseJulia:宏、表达式和 Meta.parse
【发布时间】:2019-10-24 08:10:04
【问题描述】:

以下所有这些代码行都是 Julia 表达式:

x = 10
1 + 1
println("hi")

如果你想将表达式传递给宏,它的工作方式是这样的。宏 foo 只是返回给定的表达式,它将被执行:

macro foo(ex)
  return ex
end

@foo println("yes") # prints yes

x = @foo 1+1
println(x) # prints 2

如果要将字符串转换为表达式,可以使用 Meta.parse():

string = "1+1"
expr = Meta.parse(string)
x = @foo expr
println(x) # prints 1 + 1

但是,很明显,宏将 expr 视为一个符号。我在这里做错了什么?

提前致谢!

【问题讨论】:

    标签: macros julia metaprogramming


    【解决方案1】:

    hygiene 很重要,“宏必须确保它们在返回的表达式中引入的变量不会意外地与它们扩展的周围代码中的现有变量发生冲突。” docs 中有一个部分。最简单的就是展示一个简单的案例:

    macro foo(x)
        return :($x)
    end
    

    当您在 REPL 中输入一个普通表达式时,它会立即被计算。要禁止该评估,请将表达式用:( ) 括起来。

    julia> 1 + 1
    2
    julia> :(1 + 1)
    :(1 + 1)
    # note this is the same result as you get using Meta.parse
    julia> Meta.parse("1 + 1")
    :(1 + 1)
    

    因此,Meta.parse 会将适当的字符串转换为表达式。如果你eval 结果,表达式将被评估。请注意,打印一个简单的表达式会删除外部的:( )

    julia> expr = Meta.parse("1 + 1")
    :(1 + 1)
    julia> print(expr)
    1 + 1
    julia> result = eval(expr)
    2
    

    通常,宏用于在对表达式进行通常的评估之前进行操作;它们主要是语法转换。在编译/评估/执行其他源代码之前执行宏。

    与其寻找一个评估字符串的宏,就好像它是直接输入到 REPL(不带引号)一样,而是使用这个函数。

    evalstr(x::AbstractString) = eval(Meta.parse(x))
    

    虽然我不推荐下一个宏,但了解该技术是件好事。 一个名为 <name>_str 的宏被这样使用 <name>"<string contents>"

    julia> macro eval_str(x)
              :(eval(Meta.parse($x)))
          end
    
    julia> eval"1 + 1"
    2
    

    (p.s. 不要重复使用 Base 函数名作为变量名,使用 str 而不是 string

    如果有什么我没有解决的问题,请告诉我。

    【讨论】:

    • 谢谢杰弗里,但我仍然不确定我是否明白了!归结为我的问题:表达式1+1Meta.parse("1+1") 有什么区别?因为@foo 1+1@foo Meta.parse("1+1") 不会给出相同的结果。
    • 如果我把println(typeof(ex))放在宏里面,在这两种情况下都会打印Expr...
    • 嗯,好的,expr = Meta.eval("1+1"); @foo epxr@foo Meta.eval("1+1") 不一样。
    • Meta.eval 真的不是你想要的。 eval 基本上做同样的事情并且更清晰。改用它。 str = "1 + 1"; eval(str) == str; expr = Meta.parse(str); val = eval(expr);@foo(str) == str; @foo(expr) == expr; @foo(val) == val(应该是这样)。
    • 啊,sorrrrrry,这是一个错字!我的意思是:expr = Meta.parse("1+1"); @foo epxr 与 @foo Meta.parse("1+1") 不同。我不确定我们是否只是出于不同目的而交谈。我再次尝试更清楚地说明我的问题:我必须对字符串应用什么操作,以便将其视为与 1+1 的“普通”表达式完全相同?
    猜你喜欢
    • 2020-01-26
    • 2017-07-07
    • 2017-01-16
    • 1970-01-01
    • 1970-01-01
    • 2014-12-12
    • 2018-01-09
    • 2020-06-22
    • 1970-01-01
    相关资源
    最近更新 更多