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
= do
readOctet t let (digits, rest) = Text.span Char.isDigit t
$ Left "octet does not start with a digit"
when (Text.null digits) 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
!d !f !n =
go let d' = Char.ord d - 48
= n * 10 + d'
n' 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.