提问人:Isak Hammer 提问时间:10/10/2023 最后编辑:Isak Hammer 更新时间:10/10/2023 访问量:43
在 Julia 的函数作用域的 if 语句中定义函数的错误结果
Wrong results defining a function inside a if-statement in a function scope in Julia
问:
我发现它全局工作正常有点奇怪,但在函数范围内,编译器求助于在语句中定义一个函数,我将其明确设置为 false。ifelse
尽管如此,是否有任何标准可以防止这种混淆,这种现象背后的底层编译逻辑是什么?
我不确定,但我想这个问题可能与在 Julia 中的另一个函数中有条件地定义一个函数有关。
我做了这个简单的实验。最初,我全局定义实验,一切都按预期进行。但是,当我在函数范围内运行相同的代码片段时,尽管该语句被设置为 false,但输出似乎受到该语句的影响。ifelse
# weird.jl
function experiment()
g(x) = 0
if ( true )
println("Here")
g(x) = 0
elseif (false)
g(x) = 1
end
println("We expect g(1) == 0, and we get g(1) ==", g(1))
end
g(x) = 0
if (true)
println("Here")
g(x) = 0
elseif (false)
g(x) = 1
end
println("We expect g(1) == 0, and we get g(1) ==", g(1))
println("\nExperiment")
experiment()
带输出
WARNING: Method definition g(Any) in module Main at /root/code/weird.jl:3 overwritten at /root/code/weird.jl:6.
WARNING: Method definition g(Any) in module Main at /root/code/weird.jl:6 overwritten at /root/code/weird.jl:8.
Here
We expect g(1) == 0, and we get g(1) ==0
Experiment
Here
We expect g(1) == 0, and we get g(1) ==1
关于应用程序。对我来说,总体目标是能够定义这样的函数
function lots_of_computations(mode)
# Defining variables and computations ....
if ( mode==Physical )
g_0(x, t) = 0
g_1(x) = 0
g_2(x,t) = 0
elseif (mode==General)
g_0(x, t) = 2*ε*sin(2π*t/(100*τ))*sin(2π*x[1]/L)*cos(2π*x[2]/L)
g_1(x) = ε*x[1]
g_2(x,t) = ε*t*x[2]
else
println("not supported")
end
# More computations ....
end
但是,这似乎不能在函数范围内可靠地工作。
答:
3赞
Bogumił Kamiński
10/10/2023
#1
正如 https://github.com/JuliaLang/julia/issues/15602 中所解释的(在您看到的 Julia 中的另一个函数中有条件地定义一个函数中链接),目前推荐的安全方法是使用匿名函数,因此您的代码可以看起来像:
function lots_of_computations(mode)
# Defining variables and computations ....
if mode isa Physical
g_0 = (x, t) -> 0
g_1 = x -> 0
g_2 = (x,t) -> 0
elseif mode isa General
g_0 = (x, t) -> 2*ε*sin(2π*t/(100*τ))*sin(2π*x[1]/L)*cos(2π*x[2]/L)
g_1 = x -> ε*x[1]
g_2 = (x,t) -> ε*t*x[2]
else
println("not supported")
end
# More computations ....
end
请注意,我更改为使条件是 on type of 而不是 on its value。原因是在这种情况下,语句将在编译过程中被优化出来。该条件通常也可以优化出来(由于编译器中的不断传播),但不能保证总是如此,因此通常最好根据类型而不是参数的值来设置这样的条件。mode==Physical
mode isa Physical
mode
if
mode==Physical
评论
0赞
Isak Hammer
10/10/2023
多谢!我在这个问题上绊倒了好几次:)
评论