Haskell Strict Fields
A strict field is a record field marked with a bang that is forced when its value is built. It stops a thunk from hiding inside a data value.
A strict field holds a finished number
The bang marks the field as strict. Building a Box with 7 prints the finished record.
{-# LANGUAGE BangPatterns #-}
data Box = Box { boxValue :: !Int } deriving Show
main :: IO ()
main = print (Box 7)Building a strict field forces its value
Building the strict field forces the division by zero inside evaluate. Catch turns the ArithException into a printed word.
{-# LANGUAGE BangPatterns #-}
import Control.Exception (ArithException, catch, evaluate)
data Box = Box { boxValue :: !Int } deriving Show
handler :: ArithException -> IO String
handler _ = return "caught"
main :: IO ()
main = do
outcome <- catch (evaluate (Box (1 `div` 0)) >> return "built") handler
putStrLn outcomeA lazy field can stay unevaluated
The lazy field is never printed or used. The program finishes without forcing the division by zero.
data LazyBox = LazyBox { lazyValue :: Int } deriving Show
main :: IO ()
main = let box = LazyBox (1 `div` 0) in putStrLn "lazy-built"Example
{-# LANGUAGE BangPatterns #-}
data Box = Box { boxValue :: !Int } deriving Show
main :: IO ()
main = do
print (Box (10 * 4))
print (boxValue (Box 5))Key points
- Bang: a ! before a field type marks that field as strict.
- Build time: a strict field is evaluated when the constructor runs.
- Pragma: strict fields need the BangPatterns language extension.
- Forced failure: building a strict field from a division by zero raises ArithException.
- Lazy contrast: a field without a bang can hold an unevaluated thunk.
In this example, the first print builds a Box from a product and shows the finished record. The second print reads the strict field from a Box holding 5.
Note
strict fields help when a value is always needed soon after it is built.
Try it Yourself
Edit the code, then press Run.
Running is simulated · Haskell Playground
Exercise
What does a bang on a field do?