Lazy evaluation defers computation until its result is needed. In C#, an iterator using yield return constructs each Cartesian-product tuple only when iteration requests it, unlike an eager implementation that builds every tuple immediately. section 6.1.1
Listing 6.3 The Cartesian product of two sequences
public static IEnumerable<(A a, B b)> CartesianProduct<A, B>(
this IEnumerable<A> seqa, IEnumerable<B> seqb)
{
foreach (var a in seqa)
foreach (var b in seqb)
yield return (a, b);
}
A sequence-based CartesianProduct uses nested foreach loops and yield return, turning a potentially large result into an on-demand IEnumerable sequence. section 6.1.1
The choice between eager and lazy construction changes practical behavior:
- Eager evaluation materializes all tuples up front, which may consume substantial memory for a large product. section 6.1.1
- Lazy evaluation avoids constructing unused results, but the sequence must be iterated to trigger computation. section 6.1.1
- Laziness can be treated as a capability attached to a value, alongside nullability or asynchrony. section 11.0
Mapping and binding lazy values
A Lazy<T> can be transformed with Map into a Lazy<R>: new Lazy<R>(() => func(x.Value)). If func itself returns Lazy<R>, Map creates the awkward Lazy<Lazy<R>>; Bind instead unwraps the nested workflow with new Lazy<R>(() => func(x.Value).Value). section 11.3












