I had always heard that Project Euler was a good way to try and pick up a new programming language and I’ve been meaning to try some F#, so I figured no better time than now. For those of you unfamiliar with F#, it is a functional programming language on the .NET platform. It supports object-oriented programming to a certain extent, but it isn’t considered idiomatic to use much of it. It seems more functional than scala but not to the degree of haskell or erlang.
I had some exposure to F# previously but had never actually used it. I read F# for C# Developers (which I’d recommend as a good starting resource if you are a C# dev already) and had attended a couple of talks on it. I felt that between the reading and the talks, I was in good shape to get started. So far I’ve solved about 30 problems on Project Euler using F#.
From the experience, there are a couple of little tips I thought worth sharing for others who are interested in getting started with F#, and a couple about Project Euler.
F# Tips & Tricks
- The type inference is very finicky. You should keep tabs on what type it thinks your variables are and make sure that they match what you intended. While you can specify types by hand, doing so doesn’t seem to be doing you any favors in the long term.
- The forward pipe operator (|>) and double pipe operator(||>) seem to help make a lot of elegant-looking code. The forward pipe operator takes the result of the left side and uses it as the last argument of the next function call. The double pipe takes the result of the left side as a tuple and applies the elements as arguments to the right.
- I haven’t become comfortable with the backwards pipe operator (<|) because it requires you to, effectively, read you code from right to left to understand it. That’s a difficult transition to make from the standard left to right structure. The main usage appears to be to change associativity so you don’t need parenthesis, see this link for more. I can see that there’s some value in that, but it doesn’t feel like enough of a value add for the human difficulties it’s causing. The below forward and backward pipe expressions are equivalent.
- Some of the error messages are not helpful. For example, if you attempt a fold but don’t put in the initial state argument, the compiler error is that the fold function arguments are the type that foo is, like so:
foo|> Seq.fold(fun acc elem -> acc + elem % 3)
That results in the compiler thinking both acc and elem are the same type as data because you didn’t add an initial state. Corrected so that it works looks like:
foo|> Seq.fold(fun acc elem -> acc + elem % 3) 0
- Some of the built-in libraries don’t seem complete; in particular, I’ve been finding the Array2D library missing things that I would want, like sum or fold. I realize there are some issues with folding over multidimensional data structures but it makes them more difficult to work with. I took a quick look through the docs for both Haskell and Erlang; Haskell definitely supports it and Erlang looks like it does so it’s not an intractable problem.
- There doesn’t seem to be any clear guidance on when it is the right time to use the explicit mutability capability. From what I’ve tried so far, it seems fairly safe and reasonable enough to do inside a method, but on a type it seems to cause weird performance characteristics in related code.
- When I searched for F# unit testing libraries I got a lot of hits for FsCheck but it seems like overkill for the type of coding required for Project Euler. Regular nUnit has been working fine for me. I’ll probably circle back to test out FsCheck soon, since it seemed easier to evaluate once I have some real F# under my belt.
Project Euler Tips and Tricks
- The problems on Project Euler have been flexing math muscles that have atrophied pretty badly. An added benefit is that I’ve learned some number theory stuff I had never known before.
- Unfortunately a lot of the problems are some variation on “compute this sequence then sum some chunk of it.” I’d appreciate a little more variety.
- I’d recommend problems 9, 19, 54, 59, 81-83 (variations on the same problem), 86, and 89 for others who want to check out a variety of different kinds of problems.
- Some of the problems seem to be small enough that they don’t reward an elegant number theory-derived answer, since brute forcing through the solution space is good enough.
I’ve been enjoying the experience and sort of picking and choosing problems that look interesting. I think I’ve got a pretty good grasp of the basics of F# so far. I want to take another look at FsCheck, try to build something bigger than what these problems have called for, and check out some of the web stuff as well.