The term general (contrary to specialized) in the question means the function can sort the items as long as they are of a type that is an instance of Ord.
Consider one of the most famous haskell ads
quicksort :: Ord a => [a] -> [a]
quicksort [] = []
quicksort (p:xs) = (quicksort lesser) ++ [p] ++ (quicksort greater)
where
lesser = filter (< p) xs
greater = filter (>= p) xs
The above implementation is not in-place.
I was trying to write an in-place version.
It’s easy to make quicksort in-place. Usually, we just need a mutable array and I chose Foreign.Marshal.Array.
My implementation is in-place and runs very well, but I am not satisfied with its type signature
(Ord a, Storable a) => [a] -> IO [a]
To be more precise, the type constraint Storable a annoyed me.
Obviously, if we want to sort items, Ord constraint is needed, while Storable is unnecessary.
In contrast, the type signatures of the classic quicksort or sort in Data.List, is Ord a => [a] -> [a]. The constraint is just Ord.
I didn’t find a way to get rid of the additional constraint.
I searched Stackoverflow, and found some questions about in-place quicksort in haskell, e.g.
How do you do an in-place quicksort in Haskell
Why is the minimalist, example Haskell quicksort not a "true" quicksort?
Unfortunately, their major concern is just in-place. All of the in-place quicksort examples given there have additional type constraints as well.
For example, iqsort given by klapaucius has the type signature
iqsort :: (Vector v a, Ord a) => v a -> v a
Does anyone know how to implement an in-place quicksort haskell function with type signature Ord a => [a] -> [a]?
I know how to make an in-place quicksort, but I don’t know how to make it general.
Yes it is possible. (Although in Haskell you want to use this kind of imperative algorithms only in cases where you really need top performance.)
I know of 2 such algorithms:
(Introsort is basically refined quicksort that has O(n log n) worst case complexity.)
I’m not sure about
MVector, but forMArrays, you don’t have to worry about the additional constraintsMArray a e m. They’re there to make the type more general, not less. Signatures likeallow to use the same algorithm for different array representations. For some data types, you can have specialized arrays of that type which are faster and more compact than generic arrays. For example, if you want to sort 8-bit integers, there is a specialized instance
MArray IOUArray Int8 IOfor unboxed arrays. And a specialization ofqsortfor this kind of arrays just using polymorphism isBut you also have instance
MArray IOArray e IOthat works arbitrarye. By usingqsortwithIOArray, you get a specialization without constraints one:Furthermore, if you use
STArrays and theSTmonad, you can sort an array in-place using the same function, and get the result later as a pure value, withoutIO.