Skip to content
Haskell

Laziness and Strictness

Understand lazy evaluation and when to be strict.

By EZ4Code Team
lazystrictperformance

Code

-- Lazy: undefined doesn't crash if not used
const42 :: a -> Int
const42 _ = 42
print (const42 undefined)  -- 42 (never evaluates undefined)

-- Infinite structures
primes = sieve [2..]
  where sieve (p:xs) = p : sieve [x | x <- xs, x `mod` p /= 0]
take 5 primes  -- [2,3,5,7,11]

-- Laziness can cause space leaks
sumTo :: Int -> Int
sumTo n = go n 0
  where go 0 acc = acc
        go k acc = go (k-1) (acc + k)
-- Builds a thunk: ((((0+1)+2)+3)...) — use bang patterns

sumTo' :: Int -> Int
sumTo' n = go n 0
  where go 0 acc = acc
        go k acc = let !acc' = acc + k in go (k-1) acc'
-- Forces acc' evaluation each step

-- seq and strict data fields
data StrictPair = StrictPair { _x :: !Int, _y :: !Int }

-- foldl' (strict) vs foldl (lazy)
import Data.List (foldl')
sumOk = foldl' (+) 0 [1..1000000]  -- works
sumBad = foldl  (+) 0 [1..1000000] -- space leak

Explanation

Haskell is non-strict — values are computed only when needed. This enables infinite structures and composability, but can cause space leaks (thunks accumulate). Solutions: bang patterns (!) force evaluation, seq forces a value, foldl' is strict. Strict data fields (!) prevent thunk buildup. Use strictness annotations for accumulators in recursive loops.

More Haskell Snippets