I am trying to represent standard playing cards in F#. My goal is to implement a clone of Microsoft Solitaire (the one that comes with Windows) , a game in which Cards' Suit, Face, and Color are important. This exercise is mostly intended as a way to learn some F#.
I have considered using discriminated unions:
type Suit =
| Diamonds
| Hearts
| Clubs
| Spades
type Color =
| Red
| Black
type Face =
Two | Three | Four | Five | Six | Seven |
Eight | Nine | Ten | Jack | Queen | King | Ace
with a record type for Card:
type Card = {
suit: Suit;
face: Face;
color: Color;
}
However, a Card's Color can be inferred from its Suit—all Diamonds and Hearts are Red, and all Clubs and Spades are Black. Suit cannot be determined from Color alone. Perhaps something like this is appropriate:
type Suit =
| Diamonds of Color //should always be red
| Hearts of Color //should always be red
| Clubs of Color //should always be black
| Spades of Color //should always be black
type Face =
Two | Three | Four | Five | Six | Seven |
Eight | Nine | Ten | Jack | Queen | King | Ace
type Card = {
suit: Suit;
face: Face;
}
But this doesn't seem right, since this allows incorrect combinations, e.g. Black Hearts and Red Spades.
My questions are:
Since Color
can always be inferred from Suit
, there's no reason to model it explicitly; you'll want to make illegal states unrepresentable.
You can still get a nice programming experience out of your model, and have a nice way of modelling colour, using an Active Pattern:
type Suit =
| Diamonds
| Hearts
| Clubs
| Spades
let (|Red|Black|) suit =
match suit with
| Diamonds | Hearts -> Red
| Clubs | Spades -> Black
This would enable you to pattern match on Suit
, like this inane example:
let printColor card =
match card.Suit with
| Red -> "Red"
| Black -> "Black"
Usage example from FSI:
> printColor { Suit = Spades; Face = Ace };;
val it : string = "Black"
> printColor { Suit = Diamonds; Face = King };;
val it : string = "Red"
You can add a recording method:
type Card =
{suit: Suit;face: Face}
member this.Color =
match this.suit with
| Diamonds | Hearts -> Red
| Clubs | Spades -> Black
Example:
let v = {suit = Diamonds;face = Two}
printfn "%A" v.Color
let v1 = {suit = Clubs;face = Two}
printfn "%A" v1.Color
Red Black Для продолжения нажмите любую клавишу . . .
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With