在Julia函数中重新定义函数会产生奇怪的行为

时间:2018-10-06 15:22:10

标签: julia

请考虑以下函数,这些函数的定义包含对函数的重新定义。

       TextDecoded            |  ID   |   CreatorID
Helllo, my name is Martin.    |  123  |    Martin
Yes, I wil do that tomorrow.  |  124  |    Martin

function foo1() x = 1 if x != 1 error("Wrong") end x = 2 end function foo() function p(t) return t + 1 end if p(1) != 2 error("Wrong") end function p(t) return 1 end end 运行没有错误,但是foo1()给出了错误foo()。我认为这可能与Julia不支持一般的重新定义功能有关,但我不确定。为什么会这样?

1 个答案:

答案 0 :(得分:3)

我会说这属于一个更普遍的已知问题https://github.com/JuliaLang/julia/issues/15602

在您的情况下,考虑一个更简单的功能:

function f()
    p() = "before"
    println(p())
    p() = "after"
    nothing
end

呼叫f()将打印"after"

对于您而言,您可以通过以下方式检查foo的情况:

julia> @code_typed foo()
CodeInfo(
4 1 ─     invoke Main.error("Wrong"::String)::Union{}                                                                                │
  │       $(Expr(:unreachable))::Union{}                                                                                             │
  └──     $(Expr(:unreachable))::Union{}                                                                                             │
) => Union{}

您会看到Julia优化了所有内部逻辑,只调用了error

如果您提前一步进行检查,您会看到:

julia> @code_lowered foo()
CodeInfo(
2 1 ─      p = %new(Main.:(#p#7))                                                                                                    │
3 │   %2 = (p)(1)                                                                                                                    │
  │   %3 = %2 != 2                                                                                                                   │
  └──      goto #3 if not %3                                                                                                         │
4 2 ─      (Main.error)("Wrong")                                                                                                     │
6 3 ─      return p                                                                                                                  │
)

您看到的第一行p仅分配了一次。实际上使用了第二个定义(在这里看不到,但是可以在上面看到)。

要解决您的问题,请使用如下匿名函数:

function foo2()
    p = t -> t + 1
    if p(1) != 2
        error("Wrong")
    end
    p = t -> 1
end

,一切将按预期工作。这种方法的局限性在于您不会在名称p上获得多次派发(它绑定到一个具体的匿名函数,但是我想您的示例中不需要多次派发)。