I decided quite early on that I wanted to use F# for a piece of the Ioke implementation. Josh Graham (a colleague at ThoughtWorks) suggested using it for the pieces of code doing operator shuffling. I first did a C# implementation, since it was quicker to port form Java to C#, then got that working, and finally reimplemented it in F#. The resulting code ended up being not that much smaller, but definitely more readable. I like using functional idioms if possible, but the fact of it is that the operator shuffling code is extremely imperative.
I definitely like the experience. If I can, I will aim to replace more pieces of the implementation with F#. The main problem standing in the way of that is that there doesn’t seem to be any good way of handling joint compilation. For me to use F# for real, I would need a compiler that can handle mutual interdependencies between the F# and C# code. At the moment I’m using interfaces and factories and separate modules to handle it, but that only works since the op shuffling code is very separate from the rest of the implementation. I don’t have many such pieces, so a joint compiler would be useful.
The code ended up being very clean due to the lack of type annotations and indentation for structure. This is nice. Pattern matching work very well, although the documentation on how you can combine patterns seem to be on the weak side. I had to guess my way forward.
Type annotations ended up being necessary in most code that took .NET types as arguments. This made it a bit hard to see the structure, since I ended up having to add type tags in many places. Most code will probably not be using so much .NET types, so this was a problem with what I was trying to do, I think.
The Emacs support for F# indentation ended up having trouble with the “else” in if-else statements, so I avoided if statements and went wild with patterns instead. I like the way it looks, actually.
One of the main properties of a functional language is obviously the focus on using functions for things, and this was of course one of the nicer aspects. In F# I could remove a full implementation of the Strategy pattern, and just go with curried functions instead. Instead of loops, I ended up using locally defined recursive functions. This reads really well, and feels natural for me.
The fsc compiler is extremely slow – at least on Mono. This made the turnaround cycle a bit longer then ideal. Another thing to take note of is that – just like for all other ML implementations – the error messages for type problems are way more then cryptic. Totally inscrutable, not very helpful, and generally pointing at the wrong line. This is one area where I think the F# team need to improve matters a bit. I know it’s hard with the algorithms used for type inference, but if it’s going to be part of Visual Studio 2010, good error messages and error handling is obviously important.
Oh, and the fsc –help text is totally unhelpful, and very out of date.
All in all, I really liked the experience, with the caveats above noted. I hope I can figure a good way to replace more of my internals with F#, and I am going to take a second pass at the op shuffle algorithm and see if I can make it more functional.
If you’re on the .NET platform, I recommend that you take a look at F#. It’s very nice, and allow different ways of expressing algorithms that can make your code much clearer.