【问题标题】:How to generate data idiomatically in f# inline in code如何在代码中的 f# inline 中惯用地生成数据
【发布时间】:2015-07-22 12:18:05
【问题描述】:

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

type Suit =
    | Hearts
    | Diamonds
    | Spades
    | Clubs

type Card = {
    Suit:Suit
    Rank:int
}

type Hand = {
    Cards:List<Card>
}

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

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

} 

let shuffle cards = {

}

let cards = shuffle generateCards

【问题讨论】:

标签: f# functional-programming immutability poker


【解决方案1】:

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

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())

【讨论】:

  • 你也可以Seq.sortBy (fun _ -&gt; System.Guid.NewGuid())。为卡片生成 +1,超过了我的想法。
  • 起初我打算去sortBy (fun _ -&gt; rnd.Next()),但后来我觉得实际发生的事情会更加模糊。至于Guid,一开始我也没有想到,但现在我觉得它可能比伪随机生成器对性能的影响更大。我更新了答案。
  • 我要补充一点,使用int 作为排名并不是类型系统的真正惯用用法。应该使用 DU 作为排名,可能表示为枚举。
  • 关于Guid排序见这篇文章:blog.codinghorror.com/shuffling
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-06-11
  • 1970-01-01
  • 2012-07-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多