There's an alternative approach to merging ranges. Put starting and ending points into a heap then scan it, keeping track of the number of open ranges present. Something like this:
mergeRanges rs =
let
-- We put in this order so we count openings before closings
starts = map (\(a, b) -> (a, -1)) rs
ends = map (\(a, b) -> (b, 1)) rs
heap = H.fromList (starts ++ ends) :: H.MinHeap (Int, Int)
in
mergeNo heap
where
-- not in a range currently
mergeNo :: H.MinHeap (Int, Int) -> [R]
mergeNo h =
case H.view h of
Nothing -> []
Just ((a, -1), h') -> mergeYes a 1 h'
-- in a range
mergeYes :: Int -> Int -> H.MinHeap (Int, Int) -> [R]
mergeYes start height h =
let Just ((v, delta), h') = H.view h
newHeight = height - delta
in if newHeight == 0
then (start, v) : mergeNo h'
else mergeYes start newHeight h'