Scott Nimrod
Scott Nimrod

Reputation: 11595

Discriminated Union initialization

Is there a simpler way to initialize this deck of cards using F#?

let create() = [ 0..12 ]

type Suit = 
    | Spades of list<int>
    | Hearts of list<int>
    | Clubs of list<int>
    | Diamonds of list<int>

let spades = create() |> Spades
let hearts = create() |> Hearts
let clubs = create() |> Clubs
let diamonds = create() |> Diamonds

Specifically, I would like to simplify the initialization of these four suits. Is there a simpler way to do this?

Could I enumerate the types of on this discriminated union and assign it to some "deck" structure?

NOTE:

I am new to F#. So please forgive me if this question seems ignorant.

Upvotes: 1

Views: 338

Answers (1)

Mark Seemann
Mark Seemann

Reputation: 233125

I don't think that there's a more succinct way, but I also wouldn't model playing cards like this, because it doesn't help making illegal states unrepresentable. As an example, I can do this:

> Spades [-1; 10; 100];;
val it : Suit = Spades [-1; 10; 100]

What does that even mean?


Alternative model

Instead, I'd probably model cards like this:

type Suit = Diamonds | Hearts | Clubs | Spades
type Face =
    | Two | Three | Four | Five | Six | Seven | Eight | Nine | Ten
    | Jack | Queen | King | Ace

type Card = { Suit: Suit; Face: Face }

This would enable you to express any valid card:

> { Suit = Spades; Face = Ace };;
val it : Card = {Suit = Spades;
                 Face = Ace;}

On the other hand, you can't express invalid cards:

> { Suit = Spades; Face = Hundred };;

  { Suit = Spades; Face = Hundred };;
  ------------------------^^^^^^^

stdin(4,25): error FS0039: The value or constructor 'Hundred' is not defined

Initialisation looks, in this model, a bit cumbersome, but on the other hand, the following deck is an immutable value, so once it's defined, you can reuse the deck again and again.

let deck = [
    { Suit = Diamonds; Face = Two   };
    { Suit = Diamonds; Face = Three };
    { Suit = Diamonds; Face = Four  };
    { Suit = Diamonds; Face = Five  };
    { Suit = Diamonds; Face = Six   };
    { Suit = Diamonds; Face = Seven };
    { Suit = Diamonds; Face = Eight };
    { Suit = Diamonds; Face = Nine  };
    { Suit = Diamonds; Face = Ten   };
    { Suit = Diamonds; Face = Jack  };
    { Suit = Diamonds; Face = Queen };
    { Suit = Diamonds; Face = King  };
    { Suit = Diamonds; Face = Ace   };
    { Suit = Hearts;   Face = Two   };
    { Suit = Hearts;   Face = Three };
    { Suit = Hearts;   Face = Four  };
    { Suit = Hearts;   Face = Five  };
    { Suit = Hearts;   Face = Six   };
    { Suit = Hearts;   Face = Seven };
    { Suit = Hearts;   Face = Eight };
    { Suit = Hearts;   Face = Nine  };
    { Suit = Hearts;   Face = Ten   };
    { Suit = Hearts;   Face = Jack  };
    { Suit = Hearts;   Face = Queen };
    { Suit = Hearts;   Face = King  };
    { Suit = Hearts;   Face = Ace   };
    { Suit = Clubs;    Face = Two   };
    { Suit = Clubs;    Face = Three };
    { Suit = Clubs;    Face = Four  };
    { Suit = Clubs;    Face = Five  };
    { Suit = Clubs;    Face = Six   };
    { Suit = Clubs;    Face = Seven };
    { Suit = Clubs;    Face = Eight };
    { Suit = Clubs;    Face = Nine  };
    { Suit = Clubs;    Face = Ten   };
    { Suit = Clubs;    Face = Jack  };
    { Suit = Clubs;    Face = Queen };
    { Suit = Clubs;    Face = King  };
    { Suit = Clubs;    Face = Ace   };
    { Suit = Spades;   Face = Two   };
    { Suit = Spades;   Face = Three };
    { Suit = Spades;   Face = Four  };
    { Suit = Spades;   Face = Five  };
    { Suit = Spades;   Face = Six   };
    { Suit = Spades;   Face = Seven };
    { Suit = Spades;   Face = Eight };
    { Suit = Spades;   Face = Nine  };
    { Suit = Spades;   Face = Ten   };
    { Suit = Spades;   Face = Jack  };
    { Suit = Spades;   Face = Queen };
    { Suit = Spades;   Face = King  };
    { Suit = Spades;   Face = Ace   }; ]

Although this looks tedious, you only have to write this once. Since deck is a value, you can make it a value that belongs to a module. Clients can simply use this value, instead of having to initialise a deck by themselves.

Upvotes: 5

Related Questions