在一个闭包中构造具有多个方法的函数,以及错误 "syntax: local variable T cannot be used in closure declaration"

Constructing functions with multiple methods inside a closure, and the error "syntax: local variable T cannot be used in closure declaration"

我正在研究一个 Julia 函数,该函数在一个闭包内构造一个具有多个方法的函数,return。为了简化(实际构造涉及多个非平凡的自定义类型),它看起来像这样:

function constructF(g::Function, n::Int)

    v = [g]
    for i in 2:n
        gi(x) = ForwardDiff.derivative(v[i - 1], x)
        v = vcat(v, gi)
    end

    for T in (Int, Float64) # two types but possibly more
        function f(x::T)
            acc = T(0)
            for i in 1:n
                acc += v[i](x)^i
            end
            acc
        end
    end

    return f
end

从 Julia 1.1.1 开始不支持这种代码并给了我

ERROR: LoadError: syntax: local variable T cannot be used in closure declaration
Stacktrace:
 [1] include(::String) at ./client.jl:403
 [2] top-level scope at none:0
in expression starting at /home/me/code/lang/julia/test.jl:3

替代方法如下,但会导致代码重复。

function constructF(n::Int)

    v = [g]
    for i in 2:n
        gi(x) = ForwardDiff.derivative(v[i - 1], x)
        v = vcat(v, gi)
    end

    function f(x::Int)
        acc = Int(0)
        for i in 1:n
            acc += v[i](x)^i
        end
        acc
    end

    function f(x::Float64)
        acc = Float64(0)
        for i in 1:n
            acc += v[i](x)^i
        end
        acc
    end

    # ....

    return f
end

有没有更好的写法?我研究了元编程,但文档给人的感觉不直观,我不确定如何在此处应用它。

我刚刚回答了我自己的问题。通过一些基本的元编程,我可以做到:

function constructF(g::Function, n::Int)

    v = [g]
    for i in 2:n
        gi(x) = ForwardDiff.derivative(v[i - 1], x)
        v = vcat(v, gi)
    end

    for T in (:Int, :Float64)
        @eval function f(x::$T)
            acc = $T(0)
            for i in 1:$n
                acc += $v[i](x)^i
            end
            acc
        end
    end

    return f
end

创建一个 Julia 表达式,并使用 Int、Float64 等每种类型对其求值...

您找到了一个答案,但不是 Julian 那个。

function constructF(g::Function, n::Int)

    v = [g]
    for i in 2:n
        gi(x) = ForwardDiff.derivative(v[i - 1], x)
        v = vcat(v, gi)
    end

    function f(x::T<:Number)
        acc = zero(T)
        for i in 1:n
            acc += v[i](x)^i
        end
        acc
    end

    return f
end

如果你担心不定义具体的方法会比较慢,那说明你还没有了解Julia编译器的强大。当您使用输入调用它时,它会神奇地为特定类型生成优化代码。