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

在Julia函数中重新定义函数会产生奇怪的行为,julia,Julia,考虑以下函数,其定义包含函数的重新定义 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()运行时没

考虑以下函数,其定义包含函数的重新定义

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不支持重新定义函数有关,但我不确定。为什么会发生这种情况?

我想说,这属于一个更普遍的已知问题

在你的例子中考虑一个更简单的函数:

function f()
    p() = "before"
    println(p())
    p() = "after"
    nothing
end
调用
f()
将在“
之后打印

在您的情况下,您可以通过以下方式检查
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
所有这些都将按预期工作。这种方法的局限性在于,在name
p
(它绑定到一个具体的匿名函数,但我猜在您的示例中不需要多个分派)上没有得到多个分派