如何为如下数据类型返回随机值?
datatype rank = Jack | Queen | King | Ace | Num of int
我有两个答案:要么生成唯一的每个值,要么生成所有可能的值,将它们打乱并选择一个。如果你只是想要一个孤立的随机变量,前者是最简单的。但是如果你想模拟一个纸牌游戏,其中不可能两次抽取同一张牌,那么你可能需要洗牌。
您可以看到我是如何制作command-line blackjack game 的。我将在这里重复这两种方法:
(* There are 13 card ranks, 4 suits *)
datatype rank
= Ace | Two | Three | Four | Five | Six | Seven
| Eight | Nine | Ten | Jack | Queen | King
datatype suit = Hearts | Clubs | Diamonds | Spades
datatype card = Card of suit * rank
fun concatMap f xs = List.concat (List.map f xs)
fun product xs ys = concatMap (fn x => map (fn y => (x,y)) ys) xs
val allCards = map Card
(product
[Hearts,Clubs,Diamonds,Spades]
[Ace,Two,Three,Four,Five,Six,Seven,Eight,Nine,Ten,Jack,Queen,King])
(* Create a new pseudo-random number generator, prng *)
val prng = Random.newgen ()
(* rlist determines a random index in [0 ; length xs[. *)
fun rlist xs = Random.range (0, length xs) prng
(* remove removes the n'th element of a list *)
fun remove (_, []) = raise Domain
| remove (0, card::library) = library
| remove (n, card::library) = card::remove (n-1, library);
(* randomtake removes and returns the i'th (random) element of a list *)
fun randomtake library =
let val i = rlist library
val card = List.nth (library, i)
val rest = remove (i, library)
in
(card, rest)
end
(* Shuffling is done by removing random cards until there are no cards left *)
fun shuffle [] = []
| shuffle cards =
let val (c,r) = randomtake cards
in
c :: shuffle r
end
使用这些函数,您可以通过 randomtake allCards 随机选择一张卡片,或者您可以通过第一个 shuffle allCards 选择任意数量的随机卡片而不选择同一张卡片,然后选择最上面的元素。
请注意,这些不是有效的方法。作为练习,您可以实现Fisher-Yates shuffle。