🎓 A1Learner
🔍
0 of 47 lessons completed

Haskell Strictness Analysis

Strictness analysis is the compiler working out which values a function always needs. Values it always needs can be evaluated early instead of held as unevaluated thunks.

A bang pattern forces the accumulator at once

The accumulator carries an exclamation mark. Each step forces the running total before the next step.

{-# LANGUAGE BangPatterns #-}
strictSum :: Int -> [Int] -> Int
strictSum !acc [] = acc
strictSum !acc (x:xs) = strictSum (acc + x) xs
main :: IO ()
main = print (strictSum 0 [1..100])

Seq forces a value before it is used

Seq demands its first argument. The doubled result is printed only after the input is forced.

strictDouble :: Int -> Int
strictDouble x = x `seq` (x * 2)
main :: IO ()
main = print (strictDouble 21)

A strict field is evaluated when built

The field carries an exclamation mark. Unboxing the value returns the already evaluated number.

{-# LANGUAGE BangPatterns #-}
data Box = Box !Int
unbox :: Box -> Int
unbox (Box n) = n
main :: IO ()
main = print (unbox (Box (2 + 3)))

Example

import Data.List (foldl')
main :: IO ()
main = do
  let xs = [1..1000]
  print (length xs)
  print (foldl' (+) 0 xs)

Key points

  • Strictness analysis: the compiler finding values a function always needs.
  • Thunk: an unevaluated expression waiting for its value to be demanded.
  • Bang pattern: a pattern marked with an exclamation mark that forces its value at once.
  • Seq: a function that forces its first argument before returning its second.
  • Strict field: a record or constructor field marked to be evaluated when the value is built.

In this example, the program builds the numbers from 1 to 1000, prints the length of the list, then folds it with the strict foldl' and prints the total.

Note

strictness changes when work happens, and it never changes a correct result.

Try it Yourself

Edit the code, then press Run.

Running is simulated · Haskell Playground

Exercise

What does a bang pattern on an accumulator do?