Purely functional Heap Sort in OCaml, F# and Haskell

Here's Markus Mottl's OCaml translation of Okasaki's purely functional leftist heap:

module LeftistHeap (Element : ORDERED) : (HEAP with module Elem = Element) = struct module Elem = Element type heap = E | T of int * Elem.t * heap * heap let rank = function E -> 0 | T (r,_,_,_) -> r let makeT x a b = if rank a >= rank b then T (rank b + 1, x, a, b) else T (rank a + 1, x, b, a) let empty = E let is_empty h = h = E let rec merge h1 h2 = match h1, h2 with | _, E -> h1 | E, _ -> h2 | T (_, x, a1, b1), T (_, y, a2, b2) -> if Elem.leq x y then makeT x a1 (merge b1 h2) else makeT y a2 (merge h1 b2) let insert x h = merge (T (1, x, E, E)) h let find_min = function E -> raise Empty | T (_, x, _, _) -> x let delete_min = function E -> raise Empty | T (_, x, a, b) -> merge a b end

Here's a simple OCaml heapsort based upon the same idea:

type 'a heap = E | T of int * 'a * 'a heap * 'a heap let rank = function E -> 0 | T (r,_,_,_) -> r let t(x, a, b) = let a, b = if rank a > rank b then a, b else b, a in T(rank b + 1, x, a, b) let rec merge = function | h, E | E, h -> h | (T(_, x, a1, b1) as h1), (T(_, y, a2, b2) as h2) -> if x >= y then t(x, a1, merge(b1, h2)) else t(y, a2, merge(h1, b2)) let rec to_list xs = function | E -> xs | T(_, x, a, b) -> to_list (x::xs) (merge(a, b)) let heapsort fold xs = to_list [] (fold (fun h x -> merge(t(x, E, E), h)) E xs)

This takes 0.6s to sort 100k floats on this 2× 2.0GHz E5405 Xeon and it happily sorts millions of elements.

Here's a translation to F#:

type LeftistHeap<'a> = | E | T of int * 'a * LeftistHeap<'a> * LeftistHeap<'a> let rank t = match t with E -> 0 | T (r, _, _, _) -> r let T(x, a, b) = let a, b = if rank a > rank b then a, b else b, a T(rank b, x, a, b) let rec merge h1 h2 = match h1, h2 with | h, E | E, h -> h | T(_, x, a1, b1), T(_, y, _, _) when x >= y -> T(x, a1, merge b1 h2) | T(_, x, _, _), T(_, y, a2, b2) -> T(y, a2, merge h1 b2) let rec toList xs = function | E -> xs | T(_, x, a, b) -> toList (x::xs) <| merge a b let heapSort xs = toList [] (List.fold (fun h x -> merge (T(x, E, E)) h) E xs)

This takes 1.3s and also happily sorts millions of elements.

Here's translation to Haskell:

data Heap a = E | T Int a (Heap a) (Heap a) rank E = 0 rank (T r _ _ _) = r mk x a b = if rank a > rank b then T (rank b + 1) x a b else T (rank a + 1) x b a merge h E = h merge E h = h merge h1@(T _ x a1 b1) h2@(T _ y a2 b2) = if x >= y then mk x a1 (merge b1 h2) else mk y a2 (merge h1 b2) toList xs E = xs toList xs (T _ x a b) = toList (x:xs) $ merge a b heapSort xs = toList [] (foldr (\x -> \h -> merge (mk x E E) h) E xs)

This takes 1.3 second to sort 100k floats but it stack overflows on large inputs.

Comments

Popular posts from this blog

Bjarne Stroustrup is catching up

Does reference counting really use less memory than tracing garbage collection? Mathematica vs Swift vs OCaml vs F# on .NET and Mono

Does reference counting really use less memory than tracing garbage collection? Swift vs OCaml