August 7, 2014
We move on to the next in our series on Active Patterns, but this time we’re really just covering a slight modification to the Single Total pattern that we covered in the last post.
All the same rules apply, we’re just adding the ability to add parameters to the Active Pattern.
I say ‘parameters’ but in reality I mean ‘additional parameters’. Every Active Pattern has at least one parameter. The ‘x’ in ‘match x with’ has to go somewhere.
Remember the Active Patterns we’ve seen so far are just functions. If you take away the banana clips they are identical to functions. Additional parameters are supported exactly the same way they are with regular functions.
All you need to remember is that the ‘x’ in ‘match x with’ will be passed to the last parameter of the Active Pattern. The other parameters are set by the individual lines in the Pattern Match expression.
An example might help.
Here’s the Active Pattern we used in the last post to count special characters in a string.
let (|SpecialCharacterCount|) (str: string) = let specialCharacters = "!£$%^" str.ToCharArray() |> Array.filter (fun c -> specialCharacters.Contains(c.ToString())) |> Array.length
Note the special characters are hard coded. This being a function it’s simple to turn that into a parameter.
let (|SpecialCharacterCount|) (characters: string) (str: string) = str.ToCharArray() |> Array.filter (fun c -> characters.Contains(c.ToString())) |> Array.length
You can add multiple parameters but it’s important to know how they map to the pattern matching expression that will use the Active Pattern.
Here’s code that would match against the old ‘non-parameterized’ Active Pattern
let UseThePattern (str: string) = match str with | SpecialCharacterCount c -> sprintf "That was %d special characters" c
By contrast here’s the code that uses the parameterized version
let UseThePattern (str: string) = match str with | SpecialCharacterCount "!£$%^" c -> sprintf "That was %d special characters" c
The ‘str’ in the match expression still gets passed to the last parameter of the Active Pattern, and the return value of the Active Pattern still gets assigned to ‘c’. In place of c you can still use literals just as in the last post.
The only real difference is that the extra arguments are placed between the name of the Active Pattern and the variable or literal value that we match against.
Here’s another sketch to try and hammer this home.
Apologies for spelling this out in such tedious detail but if you get what’s happening here, everything else about Active Patterns will be very simple.
Oh, and that little assignment trick we saw in the last post still works, just pass the arguments needed by the Active Pattern.
let (SpecialCharacterCount "!£$%^" c) = "ABC!" val c : int = 1
That’s it for this post and for my nemesis the Single Total Active Pattern. Next up we discover the wonders of Partial Active Patterns. We also get to rope in another interesting piece of F#, Option Types.