Skip to main content
2 of 6
deleted 3 characters in body; edited tags
Jamal
  • 34.9k
  • 13
  • 133
  • 237

Optimizing a divide-and-conquer algorithm for counting inversions in Haskell

I have the following code:

inversions :: (Ord a) => [a] -> Int
inversions xs = snd $ countInv' (xs, length xs)

countInv' :: (Ord a) => ([a], Int) -> ([a], Int)
countInv' ([], _) = ([], 0)
countInv' ([x], _) = ([x], 0)
countInv' (xs, n) = (sorted, leftInv + splitInv + rightInv)
    where
        leftLen = n `div` 2
        rightLen = n - leftLen
        (left, right) = splitAt leftLen xs
        (sortedLeft, leftInv) = countInv' (left, leftLen)
        (sortedRight, rightInv) = countInv' (right, rightLen)
        (sorted, splitInv) = countSplitInv' (sortedLeft, leftLen) (sortedRight, rightLen)

countSplitInv' :: (Ord a) => ([a], Int) -> ([a], Int) -> ([a], Int)
countSplitInv' ([], _) ([], _) = ([], 0)
countSplitInv' (xs, _) ([], _) = (xs, 0)
countSplitInv' ([], _) (xs, _) = (xs, 0)
countSplitInv' (x : xs, nx) (y : ys, ny)
    | x > y     = (y : sortedY, nx + splitInvY)
    | otherwise = (x : sortedX, splitInvX)
    where
        (sortedX, splitInvX) = countSplitInv' (xs, pred nx) (y : ys, ny)
        (sortedY, splitInvY) = countSplitInv' (x : xs, nx) (ys, pred ny)

main :: IO ()
main = do
    contents <- getContents
    print $ inversions (map read (lines contents) :: [Int])

How could I write this code in a way that is more idiomatic, reduces the amount of repetition, and reduces the amount of data being copied?

wei2912
  • 1.2k
  • 8
  • 24