为什么 tuple comprehension 生成一个 generator,而 list comprehension 生成一个 list?


#1

在 Julia 1.0.3 中,注意到如下行为:

julia> [i for i in (1,2,3)]
3-element Array{Int64,1}:
 1
 2
 3

julia> (i for i in (1,2,3))
Base.Generator{Tuple{Int64,Int64,Int64},getfield(Main, Symbol("##5#6"))}(getfield(Main, Symbol("##5#6"))(), (1, 2, 3))

可见同样是 comprehension, list comprehension 直接生成了一个 list, 因而不是 lazy 的;而 tuple comprehension (如果可以这么叫的话) 只是生成了一个 Base.Generator, 因而是 lazy 的。为什么不同时是 lazy 或不 lazy 的呢?如何让 tuple comprehension 直接 evaluate 呢?不太喜欢下面的写法,因为 Tuple 好像不是这么用的:

julia> Tuple(i for i in (1,2,3))
(1, 2, 3)

同时也不喜欢下面的写法,看起来比较丑:

julia> tuple((i for i in (1,2,3,4))...)
(1, 2, 3, 4)

当然可能 (i for i in (1,2,3)) 本省就是 generator expression, 那第一个问题(为什么不同时是 lazy的)就无效了。能请赐教一下第二个问题(好看的生成 tuple 的写法)么?


#2

我一直就是这么用的。。。(还有更好的写法么 :joy:
感觉主要是()这对括号上绑定了太多东西了。


#3

你是对的,其实是我看错了,不好意思。这应该属于

julia> methods(Tuple)
# 5 methods for generic function "(::Type)":
[1] (::Type{T})(x::Tuple) where T<:Tuple in Base at tuple.jl:229
[2] (::Type{Tuple})(nt::NamedTuple{names,T} where T<:Tuple) where names in Base at namedtuple.jl:116
[3] (::Type{T})(nt::NamedTuple) where T<:Tuple in Base at namedtuple.jl:122
[4] (::Type{Tuple})(index::CartesianIndex) in Base.IteratorsMD at multidimensional.jl:95
[5] (::Type{T})(itr) where T<:Tuple in Base at tuple.jl:243

中的第5种用法。


#4

这个语法和 Python 很像,Python 中 [i for i in (1, 2, 3)] 叫列表推导式(list comprehension),返回一个 list。
(i for i in (1, 2, 3)) 叫生成器表达式(generator expression),返回一个 generator。

Julia 里对应的文档分别是 comprehensiongenerator expression

官方文档就演示了这种用法。

主要是这里的小括号不是表示生成 tuple。


#5

嗯嗯,后来看到了,是 (::Type{T})(itr) where T<:Tuple in Base at tuple.jl:243 这种用法。