The moment I saw reverse , I felt that there could be problems. Here's a version that is more lazy and runs on infinite values. However, it depends on each of its inputs, as sorted on Day . First we aim for merge two threads
merge :: Num a => Model a -> Model a -> Model a merge (Variant xs) (Variant ys) = Variant (go xs ys) where go [] ys = ys go xs [] = xs go xx@ ((dx, vx):xs) yy@ ((dy, vy):ys) | dx < dy = (dx, vx) : go xs yy | dx > dy = (dy, vy) : go xx ys | otherwise = (dx, vx + vy) : go xs ys
This is basically the essence of what you had, but much easier. Generally, if you can make computing lazy in Haskell, then it's worth the effort, as it can be more efficient. After that we accumulate
accum :: Num a => Model a -> Model a accum (Variant xs) = Variant (go xs 0) where go [] _ = [] go ((d, v):xs) c = let c' = v + c in (d, c') : go xs c'
And then, combining these two, we get the desired result
Although, it may be better to leave merge and accum as an open API, since they can be combined in different ways, except as soon as (&+) .
It may be worth noting that the obvious way to write the accum function as a right fold
accum' :: Num a => Model a -> Model a accum' (Variant xs) = Variant (snd $ foldr go (0, []) xs) where go (d, v) (c, res) = let c' = v + c in (c', (d, c'):res)
doesn't work because it accumulates a parameter from the back of the list. The left addition attempt works, but we have to reverse the list - a double sin against laziness.
accum'' :: Num a => Model a -> Model a accum'' (Variant xs) = Variant (reverse $ snd $ foldl go (0, []) xs) where go (d, v) (c, res) = let c' = v + c in (c', (d, c'):res)
which gives a hint as to what happened in the original version. However, we can write it as a right fold, but we need to be a little complicated to transfer the battery in the right direction
accum' :: Num a => Model a -> Model a accum' (Variant xs) = Variant (foldr go (const []) xs 0) where go (d, v) rest c = let c' = v + c in (d, c') : rest c'
Note that the result of foldr go (const []) xs is a value of type a -> [a] .