I am working on an F# tutorial that creates a deck of cards. The types are listed, but I cannot understand how to loop through the types to create the map of the full deck. I expected to do something like
Foreach rank in ranks
Foreach suit in suits
somehow combine the two
next suit
next rank
Is there no way to do this? Below are the types created.
I think if I changed them from types to lists they could union, right? So, what's the point of types?
type suits=
|Spade=1
|Heart=2
|Club=3
|Diamond=4
type ranks=
|ValCard of int
|Jack
|Queen
|King
type deck= Deck of ranks * suits
An alternative approach which uses a discriminated union which meshes more nicely than enums with F#'s syntax
type suit=
|Spade
|Heart
|Club
|Diamond
static member all = [Spade;Heart;Club;Diamond]
type rank=
|ValCard of int
|Jack
|Queen
|King
static member all =([1..10]|> List.map (ValCard)) @ [Jack;Queen;King]
type card = |Card of rank * suit
let all_cards = suit.All |> List.collect (fun s -> rank.all |> List.map (fun r -> Card(r,s))
Then you can do some neat pattern matching like
all_cards
|> List.iter (fun c ->
match c with
|Card(King,Spade) -> ...
|Card(King,_) -> ...
|Card(_) -> ...
You could even define some Active patterns to get red/black cards .
Enums is a good choice for representing cards. You have comparison among suits and among ranks for free, and easily convert enums from/to int
.
type suit =
| Spade = 1
| Heart = 2
| Club = 3
| Diamond = 4
type rank =
| Ace = 1 | Two = 2 | Three = 3 | Four = 4 | Five = 5 | Six = 6 | Seven = 7
| Eight = 8 | Nine = 9 | Ten = 10 | Jack = 11 | Queen = 12 | King = 13
/// 'Card' is a type which represents a particular card
type Card = Card of rank * suit
/// 'deck' is a list consisting of all cards in a full deck
let deck = [ for r in 1..13 do
for s in 1..4 do
yield Card(enum<rank> r, enum<suit> s) ]
If you go for discriminated unions, you have to manually make lists of all suit
s and all rank
s. The advantage is better pattern matching of DUs than that of enums.
type suit =
| Spade
| Heart
| Club
| Diamond
type rank = | Ace | Two | Three | Four | Five | Six | Seven
| Eight | Nine | Ten | Jack | Queen | King
type Card = Card of rank * suit
let private suits = [Spade; Heart; Club; Diamond]
let private ranks = [Ace; Two; Three; Four; Five; Six; Seven;
Eight; Nine; Ten; Jack; Queen; King]
let deck = [ for rank in ranks do
for suit in suits do
yield Card(rank, suit) ]
As an addendum to pad's answer, you could also use reflection to generate the deck:
type Union<'T> private () =
static member val Cases =
FSharpType.GetUnionCases(typeof<'T>)
|> Array.map (fun case -> FSharpValue.MakeUnion(case, null) :?> 'T)
let deck =
[ for rank in Union<rank>.Cases do
for suit in Union<suit>.Cases do
yield Card(rank, suit) ]
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