F# by example: FizzBuzz Kata
Contents
Last Tuesday I started a book club with my friends Samir Talwar and Pedro Moreira Santos (both of them working at Codurance). The book we've choseen is "The book of F#", because we want to learn F#.
After reading the first three chapters we decided to make the FizzBuzz kata to start practicing. In this article I'm going to explain you how we solved the kata trying to explain all the F# syntax we use. So, let's start!
First of all let's install NUnit as our testing framework. In future articles we are going to take a look to other testing frameworks and libraries, but right now NUnit is a good choice.
install-package NUnit
No F# magic, just NuGet.
Let's write our first F# line of code:
https://gist.github.com/vgaltes/8900b49681c56d0c792b
In this line we have declared a new module. In F#, unless you have only one single file in your project, every file must begin with a namespace or module definition. Both are ways we have to organize our code. The main difference is that inside a module you can define other modules, type definitions, values and functions but inside a namespace only modules and type definitions.
Now we need to include NUnit in the project. To reference a package in F# (a using in C#) we use the open keyword:
https://gist.github.com/vgaltes/c1ae19b0ab531ca3ba69
As we are working in a module, we can directly write the first test:
https://gist.github.com/vgaltes/58750e89636880cda7b8
In the line 1 of this gist we can see how we use an attribute in F#, in this case the Test attribute from NUnit.
In the line 2 we are defining a new function, in this case a function without any parameter. To do that, we use the let binding to identify the function. We are not going to see any example in this article, but it's worth mentioning that let bindings are immutable.
The next interesting thing is how we name the function. In F# we can use any type of string to identify a value or a function, we just need to change what we use to wrap it. In this case we are using a quoted identifier to use a string with blank spaces, just enclosing it in backtick characters (``).
Instead of using brackets to define the body of a function in F# we use an equal after the parameter definition and we indent the body. It's no important how many whitespaces we use as long as we are consistent in the indentation level we use.
And finally, in the line 3, we are making the assertion of our test. In this case we are asserting that "1" is equals than the result of calling a function called fizzBuzz with the number 1 as a parameter. In F# we don't use parenthesis to pass parameters to a function.
Not bad for three lines of code. But this code don't compile. We need to declare the fizzBuzz function in order to be able to run the tests. Let's do it:
https://gist.github.com/vgaltes/00a56221ddaa38423688
Here we are defining a function with one argument that returns an empty string. In F#, unless we are defining a function with more that one argument and with type annotations in the arguments (we'll see type annotations later), we don't need to use parenthesis to declare a function.
In F# all expressions (and therefore all functions) returns a value, so the last expression of a function is the return value. So, in this case, the expression "" is the return value of our function.
If we now run the test, the test will fail. To make this test pass, you just only have to return "1"
https://gist.github.com/vgaltes/96c45ef56e8d2008dab9
As you can imagine, the second test will be just as the first test but changing 1 with 2. Let's see how we have to implement the function to pass it:
https://gist.github.com/vgaltes/10bd928d5d1224c8540d
Here you can see our first flow control expression, in this case an if. In F# ifs are defined with the expression if...then...else. To compare to values we use the single equal operator.
In the third test we are going to test that the fizzBuzz function returns "Fizz" when the parameter is a 3. Let's see the changes we must do in the function:
https://gist.github.com/vgaltes/6816297abd63b6f60e4f
In this case we've introduced an elif (a shortcut for else if) to specify the second condition.
After the next test ("4" = fizzBuzz 4) we have enough duplication to do a little refactor. The result of the refactor can be something like this:
https://gist.github.com/vgaltes/62018983f630c98a26b8
As you can see we can use the standard .Net ToString function here.
The next important bit is after writing tests for 6 and 9. The code of the fizzBuzz function could be something like this:
https://gist.github.com/vgaltes/cbd9ba33f5039ffb2c4e
If you follow the rule of three, it's time to refactor. Our firs refactor could be something like this:
https://gist.github.com/vgaltes/39d4f39e3dab86555200
We are using the exists function from the List module. This function takes a predicate (a function) as a first argument and the list of elements as the second one. We are checking that the input is one of the elements of the list.
We can rewrite this piece of code in a more compact way taking advantage of currying. You can read more information about currying in this post.
https://gist.github.com/vgaltes/310108e02557af31750e
With the use of the parenthesis, we are converting the = operator into a function. So, when the List.exists supplies the current list item to our predicate, we can apply the function to compare it with the input parameter.
If we continue working we will end up with something like this:
https://gist.github.com/vgaltes/651a0c64d5f4aa04b511
Now it's time to apply a typical functional feature: pattern matching. Pattern matching is F# primary branching mechanism. So, we can remove these nested ifs with a pattern matching. Pattern matching is a quite big concept (we'll explore it deeply in the future) but here we are going to apply some concepts. Let's start with the simplest refactor we can do:
https://gist.github.com/vgaltes/edafb6efc55273543a1d
Here we are matching a tuple. The underscore character (_) is the Wildcard pattern that match any value and doesn't bind it to anything.
Finally we are going to apply a couple of refactorings more to reach our final implementation:
https://gist.github.com/vgaltes/b9dc646c7a403606af46
The first refactor we made is take advantage of the NUnit's test cases to simplify the test code and remove duplication.
The second refactor is to organize the code in different modules (nested modules), one for the production code and other for the test code. In F#, the order of the modules is important because F# code is evaluated from top to bottom. So, if we need to reference module Prod from module Tests, we need to declare it before.
And that's all. I hope you liked this little F# introduction. I'll keep the blog updated with the new things we'll be learning.
Author Vicenç García
LastMod 24-04-2015