I'm trying to write a tail-recursive quicksort in Scala that works by building up a continuation, without the use of a trampoline. So far I have the following:
object QuickSort {
def sort[A: Ordering](toSort: Seq[A]): Seq[A] = {
val ordering = implicitly[Ordering[A]]
import ordering._
@scala.annotation.tailrec
def step(list: Seq[A], conts: List[Seq[A] => Seq[A]]): Seq[A] = list match {
case s if s.length <= 1 => conts.foldLeft(s) { case (acc, next) => next(acc) }
case Seq(h, tail @ _*) => {
val (less, greater) = tail.partition(_ < h)
step(less, { sortedLess: Seq[A] =>
/*
Can't use
step(greater, sortedGreater => (sortedLess :+ h) ++ sortedGreater)
and keep the tailrec annotation
*/
(sortedLess :+ h) ++ sort(greater)
} +: conts)
}
}
step(toSort, Nil)
}
}
On my computer, the above implementation works with a random sequence of at least 4000000 elements, but I have my doubts about it. Specifically, I would like to know:
- Is it stack-safe? Can we tell by just looking at the code? It compiles with
@tailrec
, but the call tosort(greater)
seems a bit suspicious. - If the answer to (1) is "No", is it possible to write a tail recursive quick sort in CPS-style in Scala that is, without using a trampoline? How ?
To be clear, I've looked at this related question that talks about how to implement a tail recursive quick sort using trampolines (which I know how to use) or your own explicit stack, but I specifically want to know if and how it can be done in a different way.