A
match
statement is a very clean way of dealing with a set of possible inputs that need to be treated in different ways. It also helps reduce the number of bugs because the compiler will complain if we haven’t specified a scenario for every possible value of the input.
When picking up a card we used an if
statement to test if the deck was empty. We could instead use a much more readable match
statement.
// ORIGINAL
let pickupCard (hand: Card list) (deck: Card list) =
if deck.Length = 0 then
failwith "No cards left!!"
else
let topcard = deck[0]
hand @ [topcard]
// WITH ~~ MATCH ~~
let pickupCard (hand: Card list) (deck: Card list) =
match deck with
| [] -> failwith "No cards left!!!"
| [a] -> hand @ [a]
| a::rest -> hand @ [a]
Line by line in the pickupCard
function:
match
on the deck
value.TIP: the compiler takes the first matching test from top to bottom. Something you need to be mindful of if you have two tests that could both possibly be true.
The most useful “special” operator that I use in F# is the pipe operator |>
The pipe operator takes whatever is on the left and “pipes” it into the function on the right as the last parameter value. i.e
b |> func a
is the same asfunc a b
What this allows us to do is chain functions together to create a bigger composite function.
let add a b = a + b let multiply a b = a * b let chained = 7 // 7 |> add 4 // 11 |> mutiply 6 // 66 |> add 2 // 68
With this knowledge we can slightly improve our newDeck
calculation to
let newDeck =
let suits = [Hearts; Diamonds; Clubs; Spades]
let numbers = [
Two; Three; Four; Five; Six; Seven; Eight; Nine; Ten;
Jack; Queen; King; Ace
]
List.allPairs suits numbers
|> List.map (fun (suit, number) -> suit number)
type CardNumber =
| Two
| Three
| Four
| Five
| Six
| Seven
| Eight
| Nine
| Ten
| Jack
| Queen
| King
| Ace
type Card =
| Hearts of CardNumber
| Diamonds of CardNumber
| Clubs of CardNumber
| Spades of CardNumber
| Joker
let hand = [Hearts Three; Diamonds Ten; Clubs King; Joker]
let newDeck =
let suits = [Hearts; Diamonds; Clubs; Spades]
let numbers = [
Two; Three; Four; Five; Six; Seven; Eight; Nine; Ten;
Jack; Queen; King; Ace
]
List.allPairs suits numbers
|> List.map (fun (suit, number) -> suit number)
let pickupCard (hand: Card list) (deck: Card list) =
match deck with
| [] -> failwith "No cards left!!!"
| [a] -> hand @ [a]
| a::rest -> hand @ [a]
;;
// DO IT!
pickupCard hand newDeck