Ruby Lazy Enumerable flat_map不是很懒惰

Chu*_*ckE 2 ruby enumerable lazy-evaluation

编辑:由于我用错误的例子写了这个问题并没有描述我的问题,我会再做一次!

在我看来,#flat_map,即使是Enumerator :: Lazy类的一部分,也不是很可枚举的.

这个例子正确地工作:

(1..Float::INFINITY).flat_map { |s| [s,s] }.take(4).to_a
Run Code Online (Sandbox Code Playgroud)

懒惰的实现也将起作用:

(1..Float::INFINITY).flat_map { |s| [s,s] }.take(4).to_a
Run Code Online (Sandbox Code Playgroud)

这只会考虑到块内生成的数组是有限的.但是在take(4)调用发生之前,它们也将被完全评估.哪个不是很懒惰.

因此,这将失败:

(1..Float::INFINITY).lazy.flat_map { |i| (i..Float::INFINITY).map(&:to_i) }.take(4).force
Run Code Online (Sandbox Code Playgroud)

因为在懒惰调用发生之前将完全评估"无限范围到数组".不过,我希望它"默认为懒惰".我的意思是,我确实理解这个难题在哪里,但我希望它以这种方式发生:flat_map评估每个实例是懒惰的,知道结果将是一个数组(或者至少是可枚举的),并将应用惰性机制在上面.因此,(i..Float :: INFINITY).map(&:to_i)将被lazified(这似乎不太兼容,因为map(&:to_i)调用将"强制"计算它).

Pat*_*ity 7

你实际上并没有使用懒惰的枚举器.要将普通枚举器转换为惰性枚举器,请使用该Enumerable#lazy方法.为了得到结果,我建议使用该方法,Enumerable::Lazy#force而不是to_a因为我认为它更清楚地显示了意图.

(1..Float::INFINITY).lazy.flat_map { |s| [s,s] }.take(4).force
#=> [1, 1, 2, 2]
Run Code Online (Sandbox Code Playgroud)