liveBook · Manning

Lazy evaluation

As explained in The Well-Grounded Rubyist, Fourth Edition

Lazy evaluation defers producing results until they are requested rather than materializing all results in advance.

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

How The Well-Grounded Rubyist, Fourth Edition covers it

How deep it goes
Explains enumerator mechanics, lazy chaining, infinite ranges, finite prefixes, and recursive aggregation through executable examples.
Examples
Demonstrates paired animal slices, infinite multiples, square sequences, and recursive powers-factorial summation.
What it assumes
Assumes familiarity with Ruby blocks, Enumerable methods, enumerators, ranges, recursion, and basic functional techniques such as currying.
What you can do after
Apply it via Ruby lazy enumerators to filter, map, and consume finite prefixes of large or infinite sequences.
How it connects
Connects lazy evaluation with enumerators, Enumerable, functional programming, recursion, currying, and partial function application.

Also explained in

Compare how 13 books explain lazy evaluation →

Related concepts

This explainer was generated by Manning's knowledge graph from the text of The Well-Grounded Rubyist, Fourth Edition. The section links point to the parts of the book it draws on.