First let’s define an Infinity constant (since Ruby does not come with one):
Inf = 1.0 / 0.0
Now let’s see if we can create a Range Object with it:
(1..Inf)
Okay, no errors. Now let’s try to use it:
(1..Inf).include?(10000000) #=> true (1..Inf).include?(-10) #=> false (-Inf..0).include?(-1000) #=> true (-Inf..Inf).include?(-1000.456) #=> true
Now let’s try using it as a ‘lazy’ list:
(1..Inf).each.take(5) #=> [1, 2, 3, 4, 5]
(1..Inf).each.take(5).select { |v| v.even? } #=> [2, 4]
(100..Inf).step(100).take(3) #=> [100, 200, 300]
One last thing:
(1..Inf).each { |v| puts v }
output:
1
2
3
4
5
...etc (quite alot of numbers...)
Applications
lazy evaluation?
Some of the applications of Lazy Enumerators (discussed here: http://www.michaelharrison.ws/weblog/?p=163) can be accomplished using Infinite Ranges instead.
In particular, the lazy_select, and lazy_map family of functions defined in that article will also work fine with Infinite Ranges:
module Enumerable
def lazy_select
Enumerator.new do |yielder|
each do |obj|
yielder.yield(obj) if yield(obj)
end
end
end
end
# first 4 even numbers
(1..Inf).lazy_select { |v| v.even? }.take(4)
output:
[2, 4, 6, 8]
Credits
This trick was discovered by Beoran in response to a question by FreakGuard in #ruby-lang on freenode.
lazy_select by gfarfl.
EDIT: Okay, this trick isn’t 100% new, see here: http://weblog.jamisbuck.org/2007/2/7/infinity
Filed under: programming, ruby | Tagged: ruby Infinity Lazy | 7 Comments »