Lazy evaluation defers producing results until a later operation requests them. In Ruby, lazy enumerators can pass values through a chain without first materializing every intermediate collection. section 10.11.1 section 16.4.1
The useful distinction is between ordinary enumerator chaining and genuinely productive lazy pipelines:
- animals.each_slice(2) carries slice-size information, allowing map to receive two-element groups as needed instead of storing every slice. section 10.11.1
- A lazy range such as (1..Float::INFINITY).lazy can represent an unbounded sequence while operations such as first request only the needed prefix. section 16.4.1
- Filtering, mapping, and taking values from lazy sequences supports recursive and functional patterns without attempting to realize infinity. section 16.4.1
Finding values in an infinite sequence
def find_multiples(num, mult) (1..Float::INFINITY).lazy.select { it % mult == 0 }.first(num) end find_multiples(3, 50) # => [50, 100, 150] The range is infinite, but first(3) requests only three matching values. The same pattern produces squares lazily, then obtains a finite prefix with squares.first(10).
def sum_powers_factorial(pfact, size)
powers = -> (power) { (1..Float::INFINITY).lazy.map
➥ { it**power } } 1
if pfact == 1
Array.new(size) { |x| x + 1 } 2
else
[powers.call(pfact).first(size),
sum_powers_factorial(pfact - 1, size)].
flatten.sum 3
end
end
>> sum_powers_factorial(4, 3)
=> 154
A recursive powers-factorial example combines lazy power sequences, finite prefixes, a terminal clause, flatten, and sum; sum_powers_factorial(4, 3) returns 154. section 16.4.1












