Sign Up

Sign Up to our social questions and Answers Engine to ask questions, answer people’s questions, and connect with other people.

Have an account? Sign In

Have an account? Sign In Now

Sign In

Login to our social questions & Answers Engine to ask questions answer people’s questions & connect with other people.

Sign Up Here

Forgot Password?

Don't have account, Sign Up Here

Forgot Password

Lost your password? Please enter your email address. You will receive a link and will create a new password via email.

Have an account? Sign In Now

You must login to ask a question.

Forgot Password?

Need An Account, Sign Up Here

Please briefly explain why you feel this question should be reported.

Please briefly explain why you feel this answer should be reported.

Please briefly explain why you feel this user should be reported.

Sign InSign Up

The Archive Base

The Archive Base Logo The Archive Base Logo

The Archive Base Navigation

  • SEARCH
  • Home
  • About Us
  • Blog
  • Contact Us
Search
Ask A Question

Mobile menu

Close
Ask a Question
  • Home
  • Add group
  • Groups page
  • Feed
  • User Profile
  • Communities
  • Questions
    • New Questions
    • Trending Questions
    • Must read Questions
    • Hot Questions
  • Polls
  • Tags
  • Badges
  • Buy Points
  • Users
  • Help
  • Buy Theme
  • SEARCH
Home/ Questions/Q 4334960
In Process

The Archive Base Latest Questions

Editorial Team
  • 0
Editorial Team
Asked: May 21, 20262026-05-21T10:36:16+00:00 2026-05-21T10:36:16+00:00

Is it possible to implement a tail recursive version of the quick sort algorithm

  • 0

Is it possible to implement a tail recursive version of the quick sort algorithm (via the continuation pattern)? And if it is, how would one implement it?

Normal (not optimized) version:

let rec quicksort list =
 match list with
 | [] -> []
 | element::[] -> [element]
 | pivot::rest -> let ``elements smaller than pivot``, ``elements larger or equal to pivot``= 
                    rest |> List.partition(fun element -> element < pivot)
                  quicksort ``elements smaller than pivot`` @ [pivot] @ quicksort ``elements larger or equal to pivot``
  • 1 1 Answer
  • 0 Views
  • 0 Followers
  • 0
Share
  • Facebook
  • Report

Leave an answer
Cancel reply

You must login to add an answer.

Forgot Password?

Need An Account, Sign Up Here

1 Answer

  • Voted
  • Oldest
  • Recent
  • Random
  1. Editorial Team
    Editorial Team
    2026-05-21T10:36:17+00:00Added an answer on May 21, 2026 at 10:36 am

    Direct style:

    let rec quicksort list =
        match list with
        | [] -> []
        | [element] -> [element]
        | pivot::rest ->
            let left, right = List.partition (fun element -> element < pivot) rest in
            let sorted_left = quicksort left in
            let sorted_right = quicksort right in
            sorted_left @ [pivot] @ sorted_right
    

    My first, naive translation is very similar to Laurent’s version, except indented a bit weirdly to make apparent that calls with continuations are really a kind of binding:

    let rec quicksort list cont =
        match list with
        | [] -> cont []
        | element::[] -> cont [element]
        | pivot::rest ->
            let left, right = List.partition (fun element -> element < pivot) rest in
            quicksort left (fun sorted_left ->
            quicksort right (fun sorted_right ->
            cont (sorted_left @ [pivot] @ sorted_right)))
    let qsort li = quicksort li (fun x -> x)
    

    Contrarily to Laurent, I find it easy to check that cont is not forgotten: CPS functions translated from direct style have the property that the continuation is used linearily, once and only once in each branch, in tail position. It is easy to check that no such call was forgotten.

    But in fact, for most runs of quicksort (supposing you get a roughly logarithmic behavior because you’re not unlucky or you shuffled the input first), the call stack is not an issue, as it only grows logarithmically. Much more worrying are the frequent calls to @ wich is linear in its left parameter. A common optimization technique is to define functions not as returning a list but as “adding input to an accumulator list”:

    let rec quicksort list accu =
        match list with
        | [] -> accu
        | element::[] -> element::accu
        | pivot::rest ->
            let left, right = List.partition (fun element -> element < pivot) rest in
            let sorted_right = quicksort right accu in
            quicksort left (pivot :: sorted_right)
    let qsort li = quicksort li []
    

    Of course this can be turned into CPS again:

    let rec quicksort list accu cont =
        match list with
        | [] -> cont accu
        | element::[] -> cont (element::accu)
        | pivot::rest ->
            let left, right = List.partition (fun element -> element < pivot) rest in
            quicksort right accu (fun sorted_right ->
            quicksort left (pivot :: sorted_right) cont)
    let qsort li = quicksort li [] (fun x -> x)    
    

    Now a last trick is to “defunctionalize” the continuations by turning them into data structure (supposing the allocation of data structures is slightly more efficient than the allocation of a closure):

    type 'a cont =
      | Left of 'a list * 'a * 'a cont
      | Return
    let rec quicksort list accu cont =
        match list with
        | [] -> eval_cont cont accu
        | element::[] -> eval_cont cont (element::accu)
        | pivot::rest ->
            let left, right = List.partition (fun element -> element < pivot) rest in
            quicksort right accu (Left (left, pivot, cont))
    and eval_cont = function
      | Left (left, pivot, cont) ->
        (fun sorted_right -> quicksort left (pivot :: sorted_right) cont)
      | Return -> (fun x -> x)
    let qsort li = quicksort li [] Return
    

    Finally, I chose the function .. fun style for eval_cont to make it apparent that those were just pieces of code from the CPS version, but the following version is probably better optimized by arity-raising:

    and eval_cont cont accu = match cont with
      | Left (left, pivot, cont) ->
        quicksort left (pivot :: accu) cont
      | Return -> accu
    
    • 0
    • Reply
    • Share
      Share
      • Share on Facebook
      • Share on Twitter
      • Share on LinkedIn
      • Share on WhatsApp
      • Report

Sidebar

Related Questions

I have a tail recursive pathfinding algorithm that I've implemented in JavaScript and would
Is it possible to implement the Visitor Pattern respecting the Open/Closed Principle , but
Is it possible to implement Bluetooth devices to provide conference rather than one-to-one operation.
How would you implement a Plugin-system for your Java application? Is it possible to
Is it possible to implement the 'not-found=ignore' behaviour of NHibernate on a key mapping
Is it possible to implement autoboxing for your own classes? To illustrate my example,
Is it possible to implement batching of multiple stored procedure calls (doing updates/deletes) in
Possible Duplicate: .NET - What’s the best way to implement a catch all exceptions
Is it possible to have an anonymous type implement an interface? I've got a
Is it possible to identify classes that implement IDisposable. I was hoping to do

Explore

  • Home
  • Add group
  • Groups page
  • Communities
  • Questions
    • New Questions
    • Trending Questions
    • Must read Questions
    • Hot Questions
  • Polls
  • Tags
  • Badges
  • Users
  • Help
  • SEARCH

Footer

© 2021 The Archive Base. All Rights Reserved
With Love by The Archive Base

Insert/edit link

Enter the destination URL

Or link to existing content

    No search term specified. Showing recent items. Search or use up and down arrow keys to select an item.