Pattern Matching in F#

Pattern matching is one of the most useful constructs in F#. Pattern matching operates on some value, matching the form of that value and altering control flow thus causing a corresponding expression to be evaluated . Lets take a look at a simple example:

let actor name = match name with | "Tom Cruise" -> "He is crazy" | _ -> "Not crazy";;

The LHS (left hand side) should look pretty familiar. Here we've defined a function called actor that takes one argument, name. On the RHS we've got the pattern matching construct using the match...with syntax. Here we're matching on the argument to the function, name. The computation of the matching is sequential so first it attempts to match the string "Tom Cruise". If the name value is "Tom Cruise" it will return the string "He is Crazy". If it does not match that string it will move on to the next pattern. In this case the next pattern is the wildcard pattern which matches everything.

For fun lets try and remove our wildcard pattern and see how the compiler/interpreter likes that:

let actor name = match name with
                        | "Tom Cruise" -> "He is crazy";;

warning: Incomplete pattern match.

As you can see, a warning was generated letting us know that our pattern match is not exhaustive. By exhaustive we mean that not all possible inputs will be matched. I wonder what happens when we try and call this function using a string we can't match on:

actor "Corey Feldman";;

Exception of type 'Microsoft.FSharp.Core.MatchFailureException' was thrown

Uh oh. What happens here is that our pattern was modified by the compiler to have a default path that generates a MatchFailureException exception. So when we called our function with a string it could match the exception was thrown. As you can see, it's good practice to define your pattern match expressions to be exhaustive.

Guarding your patterns

Guarding rules are another tool you can use when dealing with pattern matching. A guarding rule appears after your pattern and is executed if that pattern matches. The guarding rule is simply a conditional expression that if true, will evaluate the expression corresponding to that pattern. If the rule evaluates to false, control will flow to the next pattern. Below we extend the previous example to use a guarding rule:

let actor name isIceMan = match name with
                                        | "Tom Cruise" when not isIceMan -> "He is crazy"
                                        | _ -> "Not crazy";;

Now we've added the additional isIceMan argument to the function. We've also added a guarding rule to the first pattern to check whether the bool value isIceMan is true or false. If it's false the first pattern matches and the function returns "He is crazy". If it's true then we move on and try to match on the next pattern. Here's how we might use this function:

> actor "Tom Cruise" true;;
val it : string = "Not crazy"
> actor "Tom Cruise" false;;
val it : string = "He is crazy"

Lets try another pattern that's a little more difficult. Lets say that we have a list of integers and we want to return the first value in the list if it's even. If it's not, then we want to return the last value in the list if it's even. If neither of them are even we want to return 0. How could we do that? First things first, lets create a little recursive function that will walk through our list and return the last value:

let rec lastElement list = if (List.length list <= 1) then List.hd list else lastElement (List.tl list);;

Pretty simple huh? Our recursive function will return the first element in the list if the length of the list is one or less. If it's not, then it will call itself with the tail of the list. The List.tl function (tail) will return a list of everything but the first element in the list. So we'll keep removing one element until the list only has one element left, which is the last element in the original list.

Now that we have our function for getting the last element lets try our pattern:

let contrivedExample list = match list with
                                        | _ when List.hd list % 2 = 0 -> List.hd list
                                        | _ when lastElement list % 2 = 0 -> lastElement list
                                        | _ -> 0;;

Pretty simple huh? Our first pattern checks the head of the list and the second pattern uses our recursive function to check the last element. If neither is even, we return zero.

 

Leave Us a Comment!
Title (we need it)

Your Name (we need it)

Your Comment (we need it)