A tweet about some C# code rewritten in F# got me interested yesterday. "An F# rewrite of a fully refactored C# Clean Code example". Amazing. https://t.co/mplbbH1knb — Jon Harrop (@jonharrop) January 25, 2017 If you know a little F# it’s easy get sucked into thinking that having much fewer lines of code, and less noise generally makes F# code automatically better, cleaner, easier to read than C#. But, of course, that’s only true for people who know enough F# to read it.
The Problem When you want to unit test a method it’s usually pretty simple. Call the method, pass it it’s parameters and assert against it’s return value, or some other property of the object that may have changed. What happens when a method doesn’t return a value, or update some property? What happens when it leads (perhaps after some delay) to an event firing, or a callback getting called?
This week at our FunctionalKats meetup in Dublin, we tackled a simple programming task the Luhn checksum algorithm. The challenge was to try and make the code readable. I rattled off some code that worked, but I wasn’t at all happy with it. It implemented the problem as described. Partitioning the numbers into two groups and dealing with each group in turn. let Luhn s = let double x = x*2 let sumDigits = function | 18 -> 9 | n when n > 9 -> n%9 | n -> n let odds, evens = s |> Seq.
Grap The Code Mastermind, is a code breaking game for two players. A “Code Maker” creates a secret sequence of colour pegs. A “Code Breaker” must break the code by taking guesses and working with the feedback from the Code Maker. Feedback is given using Black and White Pegs. A correct colour in the correct position is acknowledged with a Black Peg A correct colour in the wrong position is acknowledged with a White Peg The position of these pegs is not significant.
Still the best job I’ve ever had and I’ve given up hoping there’ll ever be a better one. My first year at TIC was my first time in the US. Karen picked me up at the airport. On the drive to her house I mentioned Visual Basic, and there and then she decided. We would be teaching Visual Basic. That’s how things worked at TIC. During my second year I suggested we split computing and multi-media.
Here’s a really great post by Tom Moertel on squeezing every last ounce of performance out of machines back in the day. It was a time when unrolling a loop to save the few clock cycles or seeing a unique way to use the registers of a chip could take a game from clunky to classic. Stories of making machines do the impossible are the stuff of legend. The closest we mere mortals came was rejigging our config.
And so, we arrive at the last post of the series. I’ll show you the F# ‘Choice’ type and show how it relates to active patterns. I’ll explain how to add additional parameters to a multi-case active pattern, and introduce some complex pattern matching using nested active patterns. Look Ma! No Params In the previous post I mentioned that Multi-Case active patterns can’t accept additional arguments beyond the one that all active patterns must accept.
Playing Cards are a commonly used example of discriminated unions in F#. I’m not presuming that you already understand Discriminated Unions, but I’m also not going to explain them. You should be able to follow along and get a sense of how they work. If you’d like to read up on them try here. A Rank is something that can have one of 13 values Ace through King. A Suit can have one of 4 values Hearts, Clubs, Diamonds or Spades.
I’ve referred to all of the Active Patterns we have seen so far in this series as ‘Single Total’. It’s time to look at the distinction between ‘Total’ and ‘Partial’ Active Patterns. To understand Partial Active Patterns you need to have some understanding of Option Types’. If they are new to you, I’d encourage you to read up on them before continuing. A great place for reading about this, and F# generally is FSharpForFunAndProfit.
We close out the discussion of Single Active Patterns by adding parameters to the partial active pattern. If you’ve read the post on adding parameters to the Single Total Active Pattern then there is absolutely nothing new here, it works in exactly the same way. For that reason I’m not going to use this post to explain how to do it, I’m just going to work through an example and leave it at that.