2

Here's an example from Learn you a Haskell:

quicksort :: (Ord a) => [a] -> [a]
quicksort [] = []
quicksort (x:xs) =
    let smallerSorted = quicksort [a | a <- xs, a <= x]
        biggerSorted  = quicksort [a | a <- xs, a > x]
    in smallerSorted ++ [x] ++ biggerSorted

It seems that the list is iterated twice for each recursion, once for each list comprehension. Is there some magic in the compiler that optimizes this? If not, how can this be fixed?

Edit: I don't care if this is a real quicksort. Ignore the quicksort. My question is about the efficiency of the two list comprehensions, and how you can modify this specific algorithm (quicksort or not) in order to avoid iterating xs twice per recursion.

Will Ness
  • 70,110
  • 9
  • 98
  • 181
ConditionRacer
  • 4,418
  • 6
  • 45
  • 67

1 Answers1

-1

No. As of now, GHC 7.8.2 is not smart enough to figure out the clever in place quicksort algorithm from the above quicksort definition. You can do the same thing in a single pass by defining quicksort as

import Data.List (partition)
quicksort :: (Ord a) => [a] -> [a]
quicksort [] = []
quicksort (x:xs) = let (psx1, psx2, psx3) = partition3 x (x:xs) in
                   quicksort psx1 ++ psx2 ++ quicksort psx3

partition3 _ [] = ([], [], [])
partition3 a (x:xs)
    | a == x = (pxs1, x:pxs2, pxs3)
    | a < x = (pxs1, pxs2, x:pxs3)
    | a > x = (x:pxs1, pxs2, pxs3)
    where (pxs1, pxs2, pxs3) = partition3 a xs

But you should check is it possible to do quicksort of a list with only one passing? as it is more efficient than the above version.

Community
  • 1
  • 1
Priyatham
  • 2,821
  • 1
  • 19
  • 33