1

Lets say i am attempting to implement some sort of poker program in f#. Firstly is this the correct use of the type system, massive newbie here.

type Suit =
    | Hearts
    | Diamonds
    | Spades
    | Clubs

type Card = {
    Suit:Suit
    Rank:int
}

type Hand = {
    Cards:List<Card>
}

Anyway suppose i want a function to return me a randomised list of the possible holding cards. I guess there would be two functions which i would chain together, however i am having a hard time implementing them without creating a loads of objects. each of the functions in the list module will return a new list and the let keyword makes impossible to change value of the reference. what is the functional way of achieving this then. So far i have this

let generateCards = {
    let ranks = [ 1..52 ]...

} 

let shuffle cards = {

}

let cards = shuffle generateCards
Luke De Feo
  • 2,025
  • 3
  • 22
  • 40

1 Answers1

4

One way to shuffle a deck would be to zip it with a sequence of random numbers, then sort by those numbers, then unzip again.

let allCards = 
  [ for rank in 2..14 do
      for suit in [Hearts; Diamonds; Spades; Clubs] do
        yield { Suit = suit; Rank = rank } ]

let shuffle cards = 
    let rnd = System.Random()
    let rndSequence = Seq.initInfinite (fun _ -> rnd.Next())
    Seq.zip cards rndSequence |> Seq.sortBy snd |> Seq.map fst |> Seq.toList

shuffle allCards

The above could also be simplified (nod to @DaveShaw's comment), though at a cost of making it less obvious to a human, by sorting the sequence by a randomly generated key:

let shuffle cards = 
    let rnd = System.Random()
    cards |> List.sortBy (fun _ -> rnd.Next())

Or even simpler (though, possibly, with more performance impact):

let shuffle cards = List.sortBy (fun _ -> System.Guid.NewGuid()) cards

And for ultimate simplicity, go point-free style:

let shuffle = List.sortBy (fun _ -> System.Guid.NewGuid())
Fyodor Soikin
  • 78,590
  • 9
  • 125
  • 172
  • You could also do `Seq.sortBy (fun _ -> System.Guid.NewGuid())`. +1 for the card generation, beats what I had come up with. – DaveShaw May 11 '15 at 21:41
  • At first I was going to `sortBy (fun _ -> rnd.Next())`, but then I though it would be way more obscure what's actually happening. As for `Guid`, I didn't think of it at first, but now I think it may have more of a performance impact than pseudo-random generator. I updated the answer. – Fyodor Soikin May 11 '15 at 21:55
  • 1
    I would add that using `int` for a rank is not a really idiomatic use of the type system. One should use a DU for the rank, perhaps represented as an enum. – MisterMetaphor May 11 '15 at 23:29
  • Regarding sorting by Guid see this article: http://blog.codinghorror.com/shuffling/ – Huusom May 12 '15 at 07:39