对外部范围的理解会失去输出类型

时间:2015-03-02 22:42:19

标签: range list-comprehension julia

另一个新手问题,我发现这种差异非常混乱:

it = 1:3
typeof([i^2 for i in 1:3]) # Array{Int64,1}
typeof([i^2 for i in it])  # Array{Any,1}

为什么定义范围很重要?

typeof([i^2 for i in it::UnitRange{Int64}])似乎提供了一个提示,this discussion也是如此。但是,无论上述行为的原因如何,实际问题是:如何指定/强制执行理解的输出类型?

编辑:一个更全面的例子说明了两个不同的问题,

# global namespace

nu1 = 0.5 + [0 ,1:3]
nu2 = 0.5 + (0:3)
typeof([besselj(_nu,[1,2]) for _nu in nu1]) # Any
typeof([besselj(_nu,[1,2]) for _nu in nu2]) # Any
typeof([besselj(_nu,[1,2]) for _nu in 0.5 + (0:3)]) # correct inference

# within a function

function rb()
  nu = 0.5 + [0 ,1:3]
  bj   = [besselj(_nu,[1,2]) for _nu in nu]
end

function rb2()
  nu = 0.5 + (0:3)
  bj   = [besselj(_nu,[1,2]) for _nu in nu]
end

typeof(rb()) # Any
typeof(rb2())# Correct inference

我首先在函数中遇到问题,其中使用向量与范围产生不同的输出类型,并且在尝试解决此问题时,我在全局命名空间中进行了实验并遇到了另一个问题......

1 个答案:

答案 0 :(得分:4)

考虑以下代码

it = 1:3
@show typeof([i^2 for i in 1:3])
@show typeof([i^2 for i in it])

function foo()
    it = 1:3
    @show typeof([i^2 for i in 1:3])
    @show typeof([i^2 for i in it])
end

foo()

产生

typeof($(Expr(:comprehension, :(i^2), :(i = 1:3)))) => Array{Int64,1}
typeof($(Expr(:comprehension, :(i^2), :(i = it)))) => Array{Any,1}
typeof($(Expr(:comprehension, :(i^2), :(i = 1:3)))) => Array{Int64,1}
typeof($(Expr(:comprehension, :(i^2), :(i = it)))) => Array{Int64,1}

基本上,在全球范围内,类型推理要困难得多,而朱莉娅主要是在这方面做出贡献。这通常不是一个问题,因为所有"真实"代码是有条理的,不在REPL上运行。数组理解可能有时会出现类型推断问题,尽管通常有一些原因(即你是"理解" over没有具体的类型,或者你正在评估的内部函数理解不是类型稳定的)。你总是可以让Julia知道使用通常的类型向量语法输出的类型,即

it = 1:3
x = [i^2 for i in 1:3]
@show typeof(x)  # typeof(x) => Array{Int64,1}
y = Int[i^2 for i in it]
@show typeof(y)  # typeof(y) => Array{Int64,1}

但我不希望平时需要这个。当然,有些人喜欢非常清楚他们的类型断言/声明,所以你可以使用它,如果你想确定。