Of Code and Me

Somewhere to write down all the stuff I'm going to forget and then need

Exploring F#, active patterns, refactoring, rambling… October 24, 2008

Filed under: Uncategorized — Rupert Bates @ 7:11 pm
Tags: , , ,

I’ve spent some of today playing around with F# and here are the results:

I am working on a little app that takes a list of numbers does various things with them and then plots the results on a chart using the Google Charts API.
To do this I need to take an F# list of ints and convert it to a comma delimited string.

Now, if anyone knows of a library function that does this, then great, thanks, let me know and I’ll use it next time, but this time it seemed like a good opportunity to try to think about algorithms in a more functional way.

So, if I was doing this in C# I’d write something like:

    string s = "";
    foreach(int i in list)
        s += i + ",";
    return s.TrimEnd(',');

But entering into the spirit of functional programming I want to try to avoid loops and mutable state so came up with this:

let rec listAsString (l : int list) =
    match l with
        |[] -> ""
        |head::tail  ->
            if List.length tail = 1 then string tail.[0]
            else string head + "," +  listAsString tail

No mutable state, uses recursion rather than loops, great, I’m feeling pretty smug. But… that if statement looks a bit ugly, so I thought I’d see if I could find a more elegant solution.

So then I dug out a blog post by Chris Smith on active patterns and that seemed like a good solution.

So I wrote an active pattern to match the 3 states of the list that I’m interested in (empty, one element left, more than one character left)

    let (|MoreThanOne|LastElement|EmptyList|)(l : int list) =
    if List.length l = 0 then
    elif List.length l = 1 then
        LastElement(List.hd l)
        let head::tail = l
        MoreThanOne(head, tail)

And this lets me amend my function as follows:

    let rec listAsString (l : int list) =
    match l with
        |EmptyList -> ""
        |MoreThanOne(head, tail) -> string head + "," +  listAsString tail
        |LastElement x -> string x

Which seems both concise and readable.

Then I realised that actually I could do the same thing with a lot less code as follows:

let listAsString(l: int list) =
    List.fold_left (fun acc i -> acc + string i + ",") "" l
    |> fun s -> s.TrimEnd [|','|]

That is one of the things I’m enjoying about F#, there always seem to be a number of different approaches to any problem.


Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s