Benoit Daloze wrote:
> So, with Enumerator it should be:
> 
> even = Enumerator.new { |y|
>   i = 0
>   loop {
>     y << i
>     i += 2
>   }
> }
> 
> p even.take(5) # => [0, 2, 4, 6, 8]
> 
> But that is not really common practice in Ruby (Enumerator for so
> simple things).

In any case, that Enumerator block form is only syntactic sugar. You can 
do the same without using the Enumerator class:

  even = Object.new
  def even.each(&blk)
    (2..1.0/0).step(2,&blk)
  end
  even.extend Enumerable
  p even.take(5)

In both cases, all you're doing is having 'each' generate an infinite 
series, and then truncating it with 'take'.

This is not useful normally, because you can't chain it - most of the 
Enumerable  functions like 'map', 'select' etc collect the full results 
into an Array before continuing.

However, it's quite possible to have these functions process one element 
at a time without generating the intermediate arrays, and there is an 
implementation of this in the 'facets' library:


>> RUBY_VERSION
=> "1.8.6"
>> require 'rubygems'
=> true
>> require 'facets/enumerator'
=> true
>> require 'facets/enumerable/defer'
=> true
>> (1..1_000_000_000).defer.select { |i| i % 2 == 0 }.map { |i| i+100 }.take(10).to_a
=> [102, 104, 106, 108, 110, 112, 114, 116, 118, 120]


Infinite lists are no problem here - each element propagates through the 
whole chain before the next. You're processing 'horizontally' rather 
than 'vertically'.

Note that this doesn't use Threads or Fibers, it's efficient, and it 
works in ruby 1.8. For the implementation details, see the Denumerator 
class.
-- 
Posted via http://www.ruby-forum.com/.