Julia 切分元组时避免类型不稳定

Julia 切分元组时避免类型不稳定,julia,Julia,这个问题是JuliaLang Zulip帮助热线中出现的问题的改编版本 假设我有一个函数,它接受一个异构类型的元组,并将返回该元组的一个切片,其中切片索引可以仅从类型信息静态推断。如何以正确推断输出类型的方式编写函数 例如,假设我的函数是 function f(t::Tuple, A::Array{T, N}) where {T, N} if T <: AbstractFloat imin = 1 elseif T <: Integer

这个问题是JuliaLang Zulip帮助热线中出现的问题的改编版本


假设我有一个函数,它接受一个异构类型的
元组
,并将返回该元组的一个切片,其中切片索引可以仅从类型信息静态推断。如何以正确推断输出类型的方式编写函数

例如,假设我的函数是

function f(t::Tuple, A::Array{T, N}) where {T, N}
    if T <: AbstractFloat
        imin = 1
    elseif T <: Integer
        imin = 2
    else
        imin = 3
    end
    imax = N+2    
    t[imin:imax]
end 

如何编写
f
使其工作?

我最喜欢的策略(但可能有更简单的方法?)是编写
@生成的
函数,以手动确保julia在编译时执行我想要的类型级操作:

@generated function f2(t::Tuple, A::Array{T, N}) where {T, N}
    if T <: AbstractFloat
        imin = 1
    elseif T <: Integer
        imin = 2
    else
        imin = 3
    end
    imax = N+2
    out_expr = Expr(:tuple, (:(t[$i]) for i ∈ imin:imax)...)
end 

瞧,推断出的输出类型是长度为3的
元组
,其元素静态地称为
字符串
,以及
Int
Float64

您必须调用一些未报告的函数,但是您可以在不使用生成的
@函数的情况下调用这些函数,例如:

julia> function f(t::Tuple, A::Array{T, N}) where {T, N}
           t = Base.IteratorsMD.split(t, Val(N+2))[1]
           if !(T<:AbstractFloat)
               t = Base.tail(t)
               if !(T<:Integer)
                   t = Base.tail(t)
               end
           end
           return t
       end
f (generic function with 1 method)

julia> let t = (:a, "b", 2, 3.0, Val(1), 2+im), A = rand(Int, 3,3)
           Base.return_types(f, Tuple{typeof(t), typeof(A)})
       end
1-element Array{Any,1}:
 Tuple{String,Int64,Float64}
julia>函数f(t::Tuple,A::Array{t,N}),其中{t,N}
t=Base.IteratorsMD.split(t,Val(N+2))[1]
如果!(T
julia> let t = (:a, "b", 2, 3.0, Val(1), 2+im), A = rand(Int, 3,3)
           Base.return_types(f2, Tuple{typeof(t), typeof(A)})
       end
1-element Array{Any,1}:
 Tuple{String,Int64,Float64}
julia> function f(t::Tuple, A::Array{T, N}) where {T, N}
           t = Base.IteratorsMD.split(t, Val(N+2))[1]
           if !(T<:AbstractFloat)
               t = Base.tail(t)
               if !(T<:Integer)
                   t = Base.tail(t)
               end
           end
           return t
       end
f (generic function with 1 method)

julia> let t = (:a, "b", 2, 3.0, Val(1), 2+im), A = rand(Int, 3,3)
           Base.return_types(f, Tuple{typeof(t), typeof(A)})
       end
1-element Array{Any,1}:
 Tuple{String,Int64,Float64}