从字符串创建函数时的 Julia 作用域问题

Julia scoping issue when creating function from string

我想构建一个 Julia 应用程序,用户可以在其中使用配置文件(因此作为字符串)指定函数。然后需要在程序中评估函数之前解析配置文件。

问题是虽然函数名称在本地是已知的,但在包含解析器的模块中是未知的。我想到的一种解决方案是将本地 eval 函数传递给解析函数,但这似乎不太优雅。

我试图在这里提出一个最小的工作示例,其中函数名称已经包含在字符串中,而不是解析配置文件:

module MyFuns
function myfun(a)
    return a+2
end
end

module MyUtil
# in a real application, parseconfig would parse the configuration file to extract funstr
function parseconfig(funstr)
    return eval(Meta.parse(funstr))
end
function parseconfig(funstr, myeval)
    return myeval(Meta.parse(funstr))
end
end

# test 1 -- succeeds
f1 = MyFuns.myfun
println("test1: $(f1(1))")

# test 2 -- succeeds
f2 = MyUtil.parseconfig("MyFuns.myfun", eval)
println("test2: $(f2(1))")

# test 3 -- fails
f3 = MyUtil.parseconfig("MyFuns.myfun")
println("test3: $(f3(1))")

输出为:

test1: 3
test2: 3
ERROR: LoadError: UndefVarError: MyFuns not defined

那么,第二种方法可行,但是有没有更好的方法来实现目标?

Meta.parse() 会将您的字符串转换为 AST。 MyFuns.myfun 指的是什么取决于您使用的 eval() 提供的范围。

您的示例的问题在于 MyUtil 中的 eval() 将在该模块的上下文中进行计算。如果那是所需的行为,您只是想念在 MyUtil.

中使用 MyFuns

但你真正想做的是写一个宏。这允许在解析程序时将代码包含在 运行 之前。宏将有权访问一个特殊参数 __module__,这是使用宏的上下文。所以 __module__.eval() 将在那个范围内执行表达式。

foo = "outside"

module MyMod
foo = "inside"
macro eval(string)
    expr = Meta.parse(string)
    __module__.eval(expr)
end
end

MyMod.@eval "foo"

# Output is "outside"

另见关于宏的解释: https://docs.julialang.org/en/v1/manual/metaprogramming/index.html#man-macros-1

并且为了将@MauricevanLeeuwen 的答案转换为我的问题的框架,此代码将起作用:

module MyFuns
function myfun(a)
    return a+2
end
end

module MyUtil
macro parseconfig(funstr)
    __module__.eval(Meta.parse(funstr))
end
end

f4 = MyUtil.@parseconfig "MyFuns.myfun"
println("test4: $(f4(1))")