Given a list of pairs of integers that represent closed numeric intervals, I need to output a list of intervals where the adjacent intervals are merged together. The code assumes that the intervals do not overlap and that a <= b in all pairs (a, b).

Intervals (a,b) and (c,d) are adjacent if b + 1 == c.

merge []         = []
merge [x]        = [x]
merge ((a, b):(c, d):xs)
    | b + 1 == c = merge ((a, d):xs)
    | otherwise  = (a, b):(merge ((c, d):xs))

Maybe I can simplify this and use fold or something like that? Also, would converting this to a tail recursive version make sense here?


A fold isn't a great fit for this problem, they don't support any sort of pushback so you'd have to get fancy with the accumulator value and it certainly wouldn't get any prettier.

Tail recursion isn't an important concept in Haskell ([1], [2], &c). If you have a specific performance concern feel free to bring it up, but I don't see any particular reason to think your function is more likely to blow the stack than any other.

I can't come up with any appreciably simpler solutions than yours, but you might like this version which has more reusable components.

redistributeIn :: [(a, b)] -> Maybe (a, [(b, a)], b)
redistributeIn []             = Nothing
redistributeIn xs@((a0, _):_) = (a0, insides xs, b0)
    (_, b0) = last xs

    insides ((_, b):xs@((a, _):_)) = (b, a) : insides xs
    insides _                      = []

redistributeOut :: (a, [(b, a)], b) -> [(a, b)]
redistributeOut (a0, xs, b0) = outsides a0 xs b0
    outsides a_i ((b_i, a_j):xs) b_z = (a_i, b_i) : outsides a_j xs b_z
    outsides a   []              b   = (a  , b  )

merge :: [(Int, Int)] -> [(Int, Int)]
merge [] = []
merge xs = redistributeOut . second (filter (not . adjacent)) . fromJust . redistributeIn $ xs
    second f (a, b, c) = (a, f b, c)

    adjacent (a, b) = a + 1 == b

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.