首页 > 解决方案 > Julia:宏、表达式和 Meta.parse

问题描述

以下所有这些代码行都是 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 视为一个符号。我在这里做错了什么?

提前致谢!

标签: macrosjuliametaprogramming

解决方案


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

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

(ps不要重用Base函数名作为变量名,str不要使用string

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


推荐阅读