Trustbit

View Original

Introduction to Functional Programming in F# – Part 7

Introduction

Welcome to the seventh post in this introductory series on functional programming in F#. In this post we will be extending our knowledge of Pattern Matching by looking at how we can write our own matchers with Active Patterns. There are a number of different Active Patterns available but we will be concentrating on Partial & Multi-Case in this post.

Setting Up

All of the code can be written in F# script files (.fsx) and run using F# Interactive.

Partial Active Patterns

We are going to start with an old Interview favourite - FizzBuzz. Let's have a go at a simple solution;

See this content in the original post

It works but can we do better with Pattern Matching? How about this?

See this content in the original post

or this?

See this content in the original post

None of these is very readable. How about if we could do something like this?

See this content in the original post

We can use a Partial Active Pattern to do this:

See this content in the original post

The (|..|) are colloquially called 'banana clips'. Note the single '&' to apply both parts of the pattern match in the calculate function.

This is Ok but what happens if we need to add 7 -> Bazz into the mix? Look at the code now!

See this content in the original post

Maybe not such a good idea? How confident would you be that you had covered all of the permutations? Maybe a different approach would yield a better result?

See this content in the original post

This is much nicer. The fold function will concatenate all of the strings generated in the map to the original empty string.

To run the function we can use:

See this content in the original post

Let's have a look at another Interview question - Leap Years. The basic F# function looks like this:

See this content in the original post

But can Partial Active Pattern help make it more readable?

See this content in the original post

There's more code but you could easily argue that it is more readable? We could also do a similar thing to the original with helper functions rather than Active Patterns;

See this content in the original post

All three approaches are valid and it's down to preference which is best.

One area where Partial Active Patterns are really helpful is in validation and parsing. This is an example of parsing a string to a DateTime:

See this content in the original post

The only difference here is that we are returning the parsed value from the Partial Active Pattern instead of unit.

Multi-Case Active Patterns

Multi-Case Active Patterns are different from Partial Active Patterns in that they allow more than one choice and return the choice rather than an option type. The maximum number of choices supported is currently seven.

I play (rather unsuccessfully) in an online Football (the sport where participants kick a spherical ball with their feet rather than throw an egg-shaped object with their hands) Score Predictor.

The rules are simple;

  • 300 points for predicting the correct score (2-3 vs 2-3)

  • 100 points for predicting the correct result (2-3 vs 0-2)

  • 15 points per home goal & 20 points per away goal using the lower of the predicted and actual scores

We have some sample predictions, actual scores and points that we can use to validate the code we write;

See this content in the original post

Firstly we create a simple tuple type to represent a score;

See this content in the original post

To determine if we have a correct score, we need to check that the prediction and the actual score are the same. Since F# uses structural equality rather than reference equality, this is trivial with a partial active pattern;

See this content in the original post

We also need to determine what the result of a Score is. This can only one of three choices; draw, home win or away win. We can easily represent this with a multi-case active pattern;

See this content in the original post

Note that this active pattern returns one of the pattern choices rather than an option type. We can now create a new partial active pattern for determining if we have predicted the correct result;

See this content in the original post

Without the multi-case active pattern, we would have to write something like this;

See this content in the original post

I prefer the version using the Multi-Case Active Pattern. Now we need to create a function to work out the points for the goals scored;

See this content in the original post

We now have all of the parts to create our function to calculate the total points for each game;

See this content in the original post

There is a bit of duplication/similarity that we will resolve later but firstly we should use our test data to validate our code;

See this content in the original post

We can simplify our goalsScore fumction using some built in functionality of a tuple - fst and snd;

See this content in the original post

We can also simplify the calculatePoints functions by combining the pattern matching for CorrectScore and CorrectResult into a new function;

See this content in the original post

Note that we had to return 400 from CorrectScore in this function as we are no longer able to add the CorrectResult points later. This allows us to simplify the calculatePoints function;

See this content in the original post

We can use a Higher Order function to remove the duplication;

See this content in the original post

List.sumBy is equivalent to List.map followed by List.sum.

There are other types of Active Pattern that we haven't met in this post; I recommend that you investigate the F# Documentation to make yourself familiar with them.

Conclusion

Active Patterns are very useful (and powerful) features but they are not always the best approach.

In the next post we will be taking some of the features we have met in this post to add validation to the code we used in Post 6.

If you have any comments on this series of posts or suggestions for new ones, send me a tweet (@ijrussell) and let me know.

Part 6 Table of Contents Part 8