在闭包内部构造具有多个方法的函数,并且错误“语法:闭包声明中不能使用局部变量T”

时间:2019-08-05 23:12:24

标签: types scope closures julia metaprogramming

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

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

有没有更好的方法来写这个?我已经研究了元编程,但是文档看起来不直观,我不确定如何在这里应用它。

2 个答案:

答案 0 :(得分:1)

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

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等每种类型对其求值...

答案 1 :(得分:0)

您遇到的是一个答案,但不是朱利安的答案。

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编译器的强大功能。当您通过输入调用它时,它将神奇地生成针对特定类型的优化代码。