Insertion sort (Haskell)

From LiteratePrograms

Jump to: navigation, search
Other implementations: ACL2 | C | C, simple | Eiffel | Erlang | Forth | Haskell | Io | Java | Lisp | OCaml | Python | Python, arrays | Ruby | Scala, list | Smalltalk | Standard ML | Visual Basic .NET

This is a simple example of the insertion sort sorting algorithm, written in Haskell. This implementation will sort an arbitrary length list, using a user-defined sorting predicate (such as <= for a standard numerical sort).

Implementation

Insertion sort takes a predicate that compares two values of the same type. It returns a function that takes a list of that comparable type and returns a sorted version of the list.

<<insertion_sort.hs>>=
insertion_sort :: (a -> a -> Bool) -> [a] -> [a]

The empty list can already be considered sorted.

<<insertion_sort.hs>>=
insertion_sort pred []     = []

In the case of non-empty lists, we recursively insert the first element of the list into an already insertion-sorted version of the rest of the list.

<<insertion_sort.hs>>=
insertion_sort pred (x:xs) = insert pred x (insertion_sort pred xs)

So, for example

insertion_sort (<=) [5,3,10] = insert (<=) 5 (insertion_sort (<=) [3,10])
                             = insert (<=) 5 (insert (<=) 3 (insertion_sort (<=) [10]))
                             = insert (<=) 5 (insert (<=) 3 (insert (<=) 10 (insertion_sort (<=) [])))

Which reduces to

                             = insert (<=) 5 (insert (<=) 3 (insert (<=) 10 []))

since

insertion_sort pred [] = []

To further evaluate the insertion sort function, we need to understand how the insert function works.

insert

The insert function takes a predicate that compares two values of the same type, an element of the comparable type, and a list of already sorted elements. It returns another sorted list, with the insertion element correctly positioned.

<<insertion_sort.hs>>=
insert :: (a -> a -> Bool) -> a -> [a] -> [a]

An element being inserted into an empty list requires no comparisons, and can simply be returned as a list.

<<insertion_sort.hs>>=
insert pred x [] = [x]

So, from our previous example we can determine that

insert (<=) 10 [] = [10]

and we are left with

insertion_sort (<=) [5,3,10] = insert (<=) 5 (insert (<=) 3 [10])

For non-empty lists, the element being inserted, x is compared to the first element of the list, y, using the predicate pred. If the predicate evaluates to True then x is assumed to be lower in the ordering than y, and is prepended to the sorted list. Otherwise, if the predicate evaluates to false, then y is considered lower in the ordering than x, and must remain the first element in the list. The element x must then be inserted somewhere after y in the list.

<<insertion_sort.hs>>=
insert pred x (y:ys)
  | pred x y = (x:y:ys)
  | otherwise = y:(insert pred x ys)

Continuing with our example, we can see that 3 <= 10, so

insert (<=) 3 [10] = 3:10:[]
                   = [3,10]

However, 5 is not <= 3, so

insert (<=) 5 [3,10] = 3:(insert (<=) 5 [10])
                     = 3:(5:10:[])
                     = [3,5,10]

As a result

insertion_sort (<=) [5,3,10] = [3,5,10]

and the list is sorted.

Testing

The insertion sort implementation can easily be tested in an interactive Haskell environment such as Hugs or the Glasgow Haskell Compiler's GHCi. For example, after loading insertion_sort.hs into GHCi, typing

insertion_sort (<=) [1, 5, 6, 4, 3]

at the prompt produces the sorted list

[1,3,4,5,6]

Since the insertion sort implementation is generic, we can also sort non-numeric lists:

*Main> insertion_sort (<=) ["bob","alice","zoe","barry"]                
["alice","barry","bob","zoe"]
Download code
Views