将变量名称替换为 Julia 宏中的字符串

Replacing Variable Name with a String in a Julia Macro

提问人:Akhil Akkapelli 提问时间:11/1/2023 更新时间:11/2/2023 访问量:64

问:

我正在处理一个项目,我需要在 Julia 中创建一个宏,该宏将 Julia 代码表达式、变量名称和字符串作为输入,并返回相同的表达式,并将指定的变量名称替换为给定的字符串。宏必须遵循 Julia 中的变量范围,这一点很重要。

例如,如果我有以下表达式:

x = 42
expr = :(2 * x + 3)

我使用变量名称 x 和替换字符串“y”调用宏,如下所示:

@my_macro expr x "y"

我想得到修改后的表达式:

:(2 * y + 3)

我一直在尝试实现这个宏,但我在处理变量范围和确保仅针对指定变量进行替换时遇到了麻烦。

我将不胜感激在正确实现此宏方面的任何指导或帮助。如果有人对如何在 Julia 中实现这一目标有任何见解、代码片段或建议,请与我分享。

Julia 表达式

评论

1赞 BallpointBen 11/1/2023
这在宏中是不可能的——宏只能看到传递给它们的表达式,而看不到它们的值(因为宏在编译时运行,但值只存在于运行时)。如果你可以把表达式从字面上传递给宏,那么它会起作用,但你不能赋值给一个变量,然后传递给exprexpress@my_macro
0赞 Akhil Akkapelli 11/2/2023
是的,我想将表达式作为参数传递给宏

答:

3赞 Przemyslaw Szufel 11/2/2023 #1

您可以定义以下函数:

using AbstractTrees
function replace!(expr::Expr, old_val::Symbol, new_val::Symbol) 
    for e in collect(PreOrderDFS(expr))
        if typeof(e) <: Expr
            ix = findfirst(==(old_val), e.args)
            if !isnothing(ix) 
                e.args[ix] = new_val
            end
        end
    end
    expr
end

现在可以使用此功能,例如:

julia> replace!(quote; f(x,z) = 2x+4z; end, :x, :y)
quote
    #= REPL[61]:1 =#
    f(y, z) = begin
            #= REPL[61]:1 =#
            2y + 4z
        end
end

这可以在宏中使用,例如:

macro replace(mycode, oldval, newval)
    replace!(mycode, oldval.value, newval.value)
end

可用作:

julia> x=1; y=100;

julia> @replace(3x+y, :x, :y)
400

评论

0赞 Akhil Akkapelli 11/22/2023
在这里,in loop: for e in collect(PreOrderDFS(expr)),为什么修改 e.args 会反映在 expr 中,而修改 e 不会。
0赞 Przemyslaw Szufel 11/24/2023
“修改”是什么意思? 是一个局部变量,此循环包含引用。因此,我们得到一组引用作为局部变量,然后修改它们的字段。也许这会有所帮助:stackoverflow.com/questions/58150295/......ee
0赞 Akhil Akkapelli 11/24/2023
我想直接修改expr树的节点。不是 expr 的任何参数。