Skip to main content

Strictness and Unboxing

Andrew Martin provided some great feedback on my ip pull request:

This looks good. In go, put bangs on all three arguments so that we don’t rely on strictness analysis to make sure everything is unboxed. Additionally, add a type signature for go so that the types of the arguments are clear.

The updated code is as follows:

readOctet :: TextRead.Reader Word
readOctet t = do
  let (digits, rest) = Text.span Char.isDigit t
  when (Text.null digits) $ Left "octet does not start with a digit"
  case Text.foldr go Just digits 0 of
    Just n  -> Right (fromIntegral n, rest)
    Nothing -> Left ipOctetSizeErrorMsg
  where
  go :: Char -> (Int -> Maybe Int) -> Int -> Maybe Int
  go !d !f !n =
    let d' = Char.ord d - 48
        n' = n * 10 + d'
    in  if d' >= 0 && d' <=9 && n' <= 255 then f n' else Nothing

(Note: This code is written to match the style of the ip source.)

The “bang” strictness annotations helping make sure that some types are unboxed is something that I have not been considering when optimizing Haskell code lately. I do not want to forget it, and writing this blog entry helps cement it into my memory.

When I wrote the initial code, I considered the evaluation of the arguments to go and determined that they do not need strictness annotations because of the way that they are used in the function. I “hope” that GHC optimizes the code properly based on strictness analysis, but it is indeed a good idea to add the annotations and make sure.

The best reference I have found on this topic is Don Stewart’s answer to a Stack Overflow question.