The Brevity of Functional Languages

QuickSort is a well-known, efficient, sort algorithm. In previous posts I've discussed the runtime and space complexity of this algorithm, but there are some other factors that are rather important: brevity and clarity of code. Let's examine this by looking at the implementation of quicksort in C#, Java, C++ and F#.

Here is my version of quick sort in non-generic Java:

   1:      public static void quickSort(int[] input, int start, int finish)
   2:      {
   3:          if (finish-start < 2)
   4:              return;
   6:          //pick a pivot
   7:          int pivotIndex = (finish+start)/2;
   9:          //partition about the pivot
  10:          int i=start, j=finish;
  11:          while(i<=j)
  12:          {
  13:              while(input[i] < input[pivotIndex])
  14:                  i++;
  16:              while(input[j] > input[pivotIndex])
  17:                  j--;
  19:              if(i<=j)
  20:              {
  21:                  int temp = input[i];
  22:                  input[i]=input[j];
  23:                  input[j]=temp;
  24:                  i++;
  25:                  j--;
  26:              }
  27:          }
  29:          if (start < i-1)
  30:              quickSort(input, start, i-1);
  32:          if (i < finish)
  33:              quickSort(input, i, finish);        
  34:      }

And here it is in a generic C# flavour:

   1:          public static void QuickSort<T>(T[] input)
   2:                      where T : IComparable<T>
   3:          {
   4:              QuickSort(input, 0, input.Length - 1);
   5:          }
   7:          public static void QuickSort<T>(T[] input, int start, int finish)
   8:              where T:IComparable<T>
   9:          {
  10:              if (finish - start < 2)
  11:                  return;
  13:              //pick a pivot
  14:              int pivotIndex = (finish + start) / 2;
  16:              //partition about the pivot
  17:              int i = start, j = finish;
  18:              while (i <= j)
  19:              {
  20:                  while (input[i].CompareTo(input[pivotIndex]) < 0)
  21:                      i++;
  23:                  while (input[j].CompareTo(input[pivotIndex]) > 0)
  24:                      j--;
  26:                  if (i <= j)
  27:                  {
  28:                      T temp = input[i];
  29:                      input[i] = input[j];
  30:                      input[j] = temp;
  31:                      i++;
  32:                      j--;
  33:                  }
  34:              }
  36:              if (start < i - 1)
  37:                  QuickSort(input, start, i - 1);
  39:              if (i < finish)
  40:                  QuickSort(input, i, finish);
  41:          }

Here's my C++ code :

   1:  void quickSort(int arr[], int left, int right) {
   2:        int i = left, j = right;
   3:        int tmp;
   4:        int pivot = arr[(left + right) / 2];
   6:        /* partition */
   7:        while (i <= j) {
   8:              while (arr[i] < pivot)
   9:                    i++;
  10:              while (arr[j] > pivot)
  11:                    j--;
  12:              if (i <= j) {
  13:                    tmp = arr[i];
  14:                    arr[i] = arr[j];
  15:                    arr[j] = tmp;
  16:                    i++;
  17:                    j--;
  18:              }
  19:        };
  21:        /* recursion */
  22:        if (left < j)
  23:              quickSort(arr, left, j);
  24:        if (i < right)
  25:              quickSort(arr, i, right);
  26:  }

Here's some Erlang code to do the same:

qsort([]) -> [];
qsort([Pivot|T]) ->
	qsort([X || X <- T, X =< Pivot])
	++ [Pivot] ++
	qsort([X || X <- T, X > Pivot]).

And finally, here's my F# code, that admittedly does it slightly differently in that it selects the first items as the pivot:

open System
let rec quickSort ls =
  match ls with
  | [] -> []
  | p::r -> 
     quickSort [for i in r do if (compare i p) <= 0 then yield i] 
     @ [p] 
     @ quickSort [for i in r do if (compare i p) > 0 then yield i]          

I know I've mentioned it before on this site, but despite my deep admiration for C++ , Java and C# - they are all great languages - it's painfully clear that, with their advanced list comprehension syntax, functional languages are great at producing succinct code that is very easy to turn into highly parallelized code! With multi-core servers the norm these days these features of functional languages are extremely attractive.


List Comprehension in F#

List comprehension collectively refers to language features that make it easy to define lists. Often the creation of lists is based on modifications to an existing list (such as filtering it, or transforming it).

Prior to the introduction of Linq in the .NET 3.0 Framework there wasn't any real support for list comprehensions. However, since Linq came along you have all the standard query operators to query existing lists assigning the result to a new list. That all fine and dandy but the creation/initialization of lists (or arrays) was and still is rather limited in C#. There is the Enumerable class that offers the Range() and Repeat() methods but that's not at all overwhelming. Just to summarize, these Enumerable static methods can be used to perform array initialisation using fairly terse syntax as follows:

// array initialisation (for small arrays)
int[] x = Enumerable.Repeat(-1, 10).ToArray();
int[] y = Enumerable.Range(0, 10).ToArray();
int[] perfectSquares = Enumerable.Range(1, 10).Select(f => f*f).ToArray();

However, as many people found out this doesn't run nearly as fast as a simple for-loop to do the same thing. Why? Probably because Linq is iterating over the collection element by element and passing them through a lambda expression, dynamically allocation items to an array as it goes.

In F#, there is an elegant syntax called sequence expressions for generating lists, arrays and sequences (an IEnumerable is called "Seq" in F#). To create a sequence/list/array of consecutive integers you can do the following:

let seqOfLetters = seq {'A' .. 'Z'} // a sequence
let seqOfNumbers = seq {1 .. 10}    // a sequence
let listOfNumbers = [1 .. 10]       // a list
let arrayOfNumbers = [|1 .. 10|]    // an array

Note that the type of sequence generated is dependent on the bracket syntax you use.

To create non-consecutive numeric sequences (it won't work for character sequences) you can introduce a skip parameter as follows:

let seqOfEvenNumbers = seq {2 .. 2 .. 100}    // 2,4,6,8,...

Much like Linq in C#, you can also apply a filter to an existing sequence by using syntax of the following form:

seq { for pattern in container -> expr }

For example:

let listOfSquare = [ for i in 1..10 -> i*i ]

This is equivalent to the following:

let listOfSquare = [ for i in 1..10 do yield i*i ]

Don't get me wrong - I'm a big fan of C#, but there are some things that F# is better at, and list comprehension is one of them.


Project Euler: Problem 2

This problem requires that we calculate the sum of the all the even-valued terms in the Fibonacci sequence which do not exceed four million.

Using F# this is a fairly simple problem to solve. We need 3 things:

  • A function that generates Fibonacci numbers
  • A function that determines if a number is even
  • A function that determines if a number is less than another number

Clearly the last 2 parts of this are fairly trivial. You could use anonymous functions (lambdas) but since I suspect I'll need these functions again in future I've defined them as named functions in their own right. In F#, the code for these 2 functions looks like this:

let isEven i = (i%2=0)


let isLessThan x y = x < y

Now for the Fibonacci number generator. From the definition of Fibonacci numbers it is fairly easy to come up with a recursive function as follows:

// simple form

let rec fib n = if n < 2 then 1 else fib (n-2) + fib(n-1)

Or if you prefer pattern matching syntax that better deals with boundary conditions, something like this might look better:

// using parameter matching

let rec fib n =

    match n with

    | n when n<1 -> failwith "Values must be greater than 0"

    | 1 -> 1

    | 2 -> 1

    | x -> fib x-2 + fib x-1

However, both of these functions suffer from performance problems because they repeatedly calculate the same Fibonacci numbers. The answer to this problem is, of course, memoization. Adding this the code would like a little better:

// adding memoization

let fibNumbers = new Dictionary<int,int>()

fibNumbers.[1] <- 1

fibNumbers.[2] <- 1


let rec fib n =

     if n<1 then failwith "Values must be greater than 0" else

         if fibNumbers.ContainsKey(n) then fibNumbers.[n] else

            let result = fib (n-1) + fib (n-2)

            fibNumbers.[n] <- result


but there is also another issue to consider. We do not know how many numbers we will need. In this situation it's best to use a sequence rather than a finite list. A sequence is a logical series of elements all of one type. Individual sequence elements are computed only as required (lazy evaluation), so a sequence can provide performance improvements compared to a list in situations where not all the elements are used, and a sequence can produce an infinite list.

// making an infinite list (sequence)

let fibSet =

   (1I,1I) |> Seq.unfold ( fun (sqEntry, acc) -> Some (acc, (acc, acc + sqEntry)) )

Here, Seq.unfold generates a sequence from a computation function that takes a state and transforms it to produce each subsequent element in the sequence. Because each element in the Fibonacci sequence is the sum of the previous two Fibonacci numbers, the state value is a tuple that consists of the previous two numbers in the sequence. The initial value is (1,1), the first two numbers in the sequence. The I suffix is used to denote a BigInteger type.

We can now compose all these functions to solve the problem. We simply iterate over the sequence (infinite list) until we reach our termination criteria (the Fibonacci number exceeds 4 million), summing the numbers as we go.

// making an infinite list (sequence)

let fibSet =

   (1I,1I) |> Seq.unfold ( fun (sqEntry, acc) -> Some (acc, (acc, acc + sqEntry)) )


// use this if you want to print out the first c numbers in the sequence

let printfibNumberSet c =

    for x in 1..c do

        printf "%A," (fib x)


// utility functions

let isEven i = (i%2I=0I)


let isLessThan x y = x < y


// making an infinite list (sequence)

let euler2 = fibSet

                |> Seq.takeWhile (fun x -> (isLessThan x 4000000I))

                |> Seq.filter (fun x -> isEven x)

                |> Seq.sum


printfn "%A" euler2

Console.ReadLine() |> ignore

One final note...there is a closed-form solution to calculating the n-th Fibonacci number.

It's called Binet's formula and it can be formulated as follows in F#:

let phi = (1.0 + sqrt 5.0)/2.0

let fibN n = Math.Round((phi**n - (1.0 - phi)**n)/(sqrt 5.0) , MidpointRounding.AwayFromZero )

If you don't want a recursive formula you can use this approach.


Next »