xzhu
xzhu

Reputation: 5755

What's the common fast way of expressing the infinite enumerator `(1..Inf)` in Ruby?

I think infinite enumerator is very convenient for writing FP style scripts but I have yet to find a comfortable way to construct such structure in Ruby.

I know I can construct it explicitly:

a = Enumerator.new do |y|
    i = 0
    loop do
        y << i += 1
    end
end
a.next  #=> 1
a.next  #=> 2
a.next  #=> 3
...

but that's annoyingly wordy for such a simple structure.

Another approach is sort of a "hack" of using Float::INFINITY:

b = (1..Float::INFINITY).each
b = (1..1.0/0.0).each

These two are probably the least clumsy solution I can give. Although I'd like to know if there are some other more elegant way of constructing infinite enumerators. (By the way, why doesn't Ruby just make inf or infinity as a literal for Float::INFINITY?)

Upvotes: 5

Views: 90

Answers (3)

pvandenberk
pvandenberk

Reputation: 4798

Ruby 2.7 introduced Enumerator#produce for creating an infinite enumerator from any block, which results in a very elegant, very functional way of implementing the original problem:

irb(main):001:0> NaturalNumbers = Enumerator.produce(0) { |x| x + 1 }
=> #<Enumerator: #<Enumerator::Producer:0x00007fadbd82d990>:each>
irb(main):002:0> NaturalNumbers.first(10)
=> [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
irb(main):003:0> _

... which - if you're a fan of numbered block parameters (another Ruby 2.7 feature) - can also be written as:

irb(main):006:0> NaturalNumbers = Enumerator.produce(0) { _1 + 1 }
=> #<Enumerator: #<Enumerator::Producer:0x00007fadbc8b08f0>:each>
irb(main):007:0> NaturalNumbers.first(10)
=> [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
irb(main):008:0> _

Upvotes: 0

Todd A. Jacobs
Todd A. Jacobs

Reputation: 84343

Use #to_enum or #lazy to convert your Range to an Enumerable. For example:

(1..Float::INFINITY).to_enum
(1..Float::INFINITY).lazy

Upvotes: 2

ianks
ianks

Reputation: 1768

I would personally create my own Ruby class for this.

class NaturalNumbers
  def self.each
    i = 0
    loop { yield i += 1 }
  end
end

NaturalNumbers.each do |i|
  puts i
end

Upvotes: 1

Related Questions