如何在代码内联的 f# 中以惯用方式生成数据

How to generate data idiomatically in f# inline in code

假设我正在尝试在 f# 中实现某种扑克牌程序。首先是类型系统的正确使用,这里是大量的新手。

type Suit =
    | Hearts
    | Diamonds
    | Spades
    | Clubs

type Card = {
    Suit:Suit
    Rank:int
}

type Hand = {
    Cards:List<Card>
}

无论如何,假设我想要一个函数来 return 给我一个可能持有卡片的随机列表。我想我会把两个函数链接在一起,但是我很难在不创建大量对象的情况下实现它们。 list 模块中的每个函数都会 return 一个新列表,并且 let 关键字使得无法更改引用的值。那么实现这一目标的功能方法是什么。到目前为止我有这个

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

} 

let shuffle cards = {

}

let cards = shuffle generateCards

洗牌的一种方法是用一系列随机数压缩它,然后按这些数字排序,然后再次解压缩。

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

上面的内容也可以简化(点头@DaveShaw 的评论),但代价是通过随机生成的键对序列进行排序,使它对人类来说不那么明显:

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

或更简单(尽管可能对性能影响更大):

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

为了最简单,使用无点样式:

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