问题
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:
- What is the most idiomatic way to handle Suit and Color, considering that Color is dependent on Suit?
- Should the concept of Color even be explicitly represented? One could theoretically just replace all occurrences of Color with pattern matches against Diamonds or Hearts (which are red) and Clubs or Spades (which are black).
回答1:
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"
回答2:
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 Для продолжения нажмите любую клавишу . . .
来源:https://stackoverflow.com/questions/29001670/f-modeling-playing-cards