Я пытаюсь написать хвостохранилище в Scala, которое работает, создавая продолжение, без использования батута. До сих пор у меня есть следующий:Рекурсивный хвост Стиль продолжения Quicksort в Scala
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)
}
}
На моем компьютере, выше реализация работает со случайной последовательностью, по меньшей мере, 4000000 элементов, но у меня есть сомнения по этому поводу. В частности, я хотел бы знать:
- Безопасен ли он? Можем ли мы просто взглянуть на код? Он компилируется с
@tailrec
, но вызовsort(greater)
выглядит несколько подозрительным. - Если ответ на (1) - «Нет», можно ли написать хвостовую рекурсивную быструю сортировку в стиле CPS в Scala, то есть без использования батута? Как ?
Чтобы было ясно, я смотрел на this related question, что говорит о том, как реализовать хвост рекурсивной быструю сортировку, используя батуты (который я знаю, как использовать) или собственный явный стек, но я определенно хочу знать, если и как это можно сделать по-другому.
Ах да, я понимаю, что я торгую стекю для кучи, и что, учитывая достаточно большую проблему, этот трюк CPS (и связанные с ним варианты батут/свободная монада) взорвет мою кучу. Я предполагаю, что интуитивно, тот факт, что вызов 'sort' находится в куче, безопасен, имеет смысл; но мое понимание того, почему именно немного нечеткое и ручное. – lloydmeta