在 Julia 的函数作用域的 if 语句中定义函数的错误结果

Wrong results defining a function inside a if-statement in a function scope in Julia

提问人:Isak Hammer 提问时间:10/10/2023 最后编辑:Isak Hammer 更新时间:10/10/2023 访问量:43

问:

我发现它全局工作正常有点奇怪,但在函数范围内,编译器求助于在语句中定义一个函数,我将其明确设置为 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

但是,这似乎不能在函数范围内可靠地工作。

函数 if-statement 作用域 Julia 编译器警告

评论


答:

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==Physicalmode isa Physicalmodeifmode==Physical

评论

0赞 Isak Hammer 10/10/2023
多谢!我在这个问题上绊倒了好几次:)