BudiBadu Logo
Samplebadu

Haskell by Example: Lazy Evaluation

GHC 9.x

Working with infinite data structures through this code example demonstrating non-strict evaluation strategy, infinite list definitions, thunk creation for suspended computations, and demand-driven computation with take and filter.

Code

-- An infinite list of all integers starting from 1
naturals :: [Integer]
naturals = [1..]

-- An infinite list of Fibonacci numbers
fibs :: [Integer]
fibs = 0 : 1 : zipWith (+) fibs (tail fibs)

-- Taking the first 10 items from an infinite list
firstTenFibs :: [Integer]
firstTenFibs = take 10 fibs

-- Filtering an infinite list
firstLargeFib :: Integer
firstLargeFib = head (filter (> 1000) fibs)

Explanation

Haskell uses lazy evaluation as its primary execution strategy, meaning expressions are not computed until their values are actually needed. This non-strict evaluation allows defining infinite data structures like [1..] representing all natural numbers without causing memory exhaustion or infinite loops. Expressions create thunks, suspended computations containing the expression and its environment, which are evaluated only when demanded.

Lazy evaluation benefits include:

  • Infinite data structures become practical, computing only demanded portions
  • Thunks are shared and memoized, avoiding redundant calculations
  • Improved modularity separating data generation from consumption logic
  • Conditional branches evaluate only the taken path, not all alternatives
  • Evaluation to Weak Head Normal Form (WHNF) computes only outermost constructor

The Fibonacci example demonstrates self-referential infinite lists where fibs is defined using itself through zipWith. Laziness ensures only requested elements are calculated. Functions like take 10 consume finite portions, while filter (> 1000) searches the infinite sequence until finding the first match. Potential downsides include space leaks from accumulated thunks, mitigated using strict evaluation functions like seq or foldl'.

Code Breakdown

3
[1..] infinite list, laziness prevents infinite computation.
7
zipWith (+) fibs (tail fibs) self-referential definition works via lazy evaluation.
11
take 10 consumer forces evaluation of first 10 elements only.
15
filter (> 1000) searches infinite list until predicate satisfied.