F# modeling playing cards

妖精的绣舞 提交于 2019-11-27 07:50:10

问题


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:

  1. What is the most idiomatic way to handle Suit and Color, considering that Color is dependent on Suit?
  2. 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

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!