朱莉娅:宏,表达式和Meta.parse

时间:2019-10-24 08:10:04

标签: macros julia metaprogramming

下面所有这些代码行都是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视为符号。我这是怎么了?

谢谢!

1 个答案:

答案 0 :(得分:3)

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。请勿将基本函数名称重复用作变量名称,请使用str而不是string

请让我知道是否有我未解决的问题。