Pattern Matching
Pattern matching is pretty great. Essentially, it lets us match stuff.
The verbose (although not very) syntax is:
let equalToTen x = match x with | 10 -> printfn "Equal to ten!" | _ -> printfn "Not equal to ten!"
Or, we can do this:
let equalToTen = function | 10 -> printfn "Equal to ten!" | _ -> printfn "Not equal to ten!"
If you hadn’t figured it out, _ is the wildcard. If you don’t have a wildcard and don’t get a match, you’ll have a MatchFailureException thrown.
We can also pattern match our own types of course.
type Language = { Name : string } let checkLanguage x = match x with | { Name= "F#"} -> printfn "We've got a winner! F#!" | { Name= "C#"} -> printfn "We've got C#! Not bad." | _ -> printfn "Really? Try F# instead!" do checkLanguage { Name = "F#"} do checkLanguage { Name = "C#"} do checkLanguage { Name = "Java"}
If we start working with tuples, we get access to a lovely range of pattern matching things. A quick aside first: tuples in F# are very simple. They are represented inside brackets and can have as many values as you want.
let tuple = (1, 2) let child = ("Age", 5) let vowels = ("A", "E", "I", "O", "U") let singlePositiveIntegers = (0, 1, 2, 3, 4, 5, 6, 7, 8, 9)
So, back to pattern matching.
We can pattern match tuples based on a variety of things, such as checking a specific part of the tuple, or comparing the left hand side of a tuple of 2 with the right hand side.
let tupleCompare = function | (0, 0) -> printfn "Tuple of two zeroes" | (0, _) | (_, 0) -> printfn "Tuple of one zero" | (a, b) when a > b -> printfn "Tuple with a larger lhs" | (a, b) when a < b -> printfn "Tuple with a larger rhs" | (a, b) -> printfn "Tuple that's equal and non-zero" | _ -> printfn "Do you think it's possible to get here?" tupleCompare (0, 0) tupleCompare (0, 1) tupleCompare (1, 0) tupleCompare (2, 1) tupleCompare (1, 2) tupleCompare (2, 2)
You also hopefully noted there that you can use | as an or operator, to combine multiple matches, and that you can also use when to perform comparisons.
We can do this sort of matching with lists, discriminated unions and arrays, too. It’s really a very powerful way to work with your data.
Hi, nice article – but just a pointer here in case you did not realise, when you use the function keyword, it is shorthand for “this takes one parameter which isn’t explicitly named, and is immediately matched on” therefore, “let equalToTen x = match x with … ” is the same as “let equalToTen = function …”
If you write “let equalToTen x = function …” you are essentially creating a function that accepts two parameters, one is x and the other is a unnamed parameter that has to be immediately matched on.
Ross
[…] Alex Hardwicke blogged “Pattern Matching“. […]
You are of course completely correct! That was a mistake on my part (which I’ve now fixed), but I really appreciate the comment. That’s what I get for not testing my code!
I’m still learning F# (I’m blogging about F# to help me understand it better by going over what I’ve learnt), and it’s the great F# community that are really helping me along, so thanks again.
Hi, nice post. One other point – in your last code sample, if you want to know if the wildcard case is necessary or not, you can simply remove it – the compiler will automatically flag a warning with a sample case that isn’t covered 🙂
Yeah, I just put it in there as a sort of exercise for the reader (hence the question). Unless I’m wrong though, the wildcard isn’t needed as it demands a tuple and (a, b) will match all tuples that haven’t already been matched.