My Haskell set/map/list folds often become terse and difficult to read. I'm looking for tips on how to make my functional code easier to follow.
I'm working around a bug/feature in a plotting library. I have a map from tags to lists of (time,count) which I plot as a stacked graph:
import Data.Time (UTCTime)
import qualified Data.Map as M
import qualified Data.Set as S
type CountMap = M.Map String [(UTCTime, Int)]
-- Data used for plotting data series 'foo' and 'bar'
test :: CountMap
test =
M.fromList [ ("foo", [(read "2012-09-28 12:00:00", 3), (read "2012-09-29 12:00:00", 4)])
, ("bar", [(read "2012-09-28 12:00:00", 3)])
]
You will note that the above "bar" series is missing a sample for 2012-09-29. I need to fill these gaps with zeros before I pass the data to the plotting library.
The same data with the gaps closed becomes:
fromList [ ("bar",[(2012-09-28 12:00:00 UTC,3),(2012-09-29 12:00:00 UTC,0)])
, ("foo",[(2012-09-28 12:00:00 UTC,3),(2012-09-29 12:00:00 UTC,4)])]
The code I use for filling the gaps with zero samples is as follows:
import Data.Time (UTCTime)
import qualified Data.Map as M
import qualified Data.Set as S
-- Insert zero counts into date buckets that are missing a sample.
substZeroCount :: CountMap -> CountMap
substZeroCount m =
M.map zeros m
where
allDates = M.fold (flip (foldr (\(date,_) -> S.insert date))) S.empty m
zeros cs = M.toList $ S.fold insertMissing (M.fromList cs) allDates
insertMissing date acc = if M.member date acc then acc else M.insert date 0 acc
It works and it's not even too long. But somehow I don't feel happy about its readability. It looks somehow too terse. Maybe it's just about code layout.. or perhaps there'd be a nicer way to compose these functions. Or maybe it's just because a lot happens in 3 lines of code. ;)
Any suggestions on how to make substZeroCount easier on the eyes?