List F#系统。在递归函数中随机做一些有趣的事情

List F#系统。在递归函数中随机做一些有趣的事情,list,recursion,random,f#,List,Recursion,Random,F#,我有一个功能,可以选择4种随机颜色并列出它。至少我也想要它 let theList = [Red;Green;Yellow;Purple;White;Black] let rec a x = let rnd = System.Random() match x with |0 -> [] |_ -> (List.item(rnd.Next(6)) theList)::(a (x-1)) 问题是,虽然每次我运行funktion时它都会随机选择一种颜色,但它总是为整个

我有一个功能,可以选择4种随机颜色并列出它。至少我也想要它

let theList = [Red;Green;Yellow;Purple;White;Black]
let rec a x =
  let rnd = System.Random()
  match x with 
  |0 -> []
  |_ -> (List.item(rnd.Next(6)) theList)::(a (x-1)) 
问题是,虽然每次我运行funktion时它都会随机选择一种颜色,但它总是为整个列表选择相同的颜色。[红色;红色;红色;红色]或[绿色;绿色;绿色]等

对于我来说,它是一个谜,它如何在每次进行递归调用时都能得到相同的颜色

如果我在for循环中使用random方法,那么没有问题


有人能给我解释一下这里发生了什么吗?

把你的
系统.Random()
调出函数,它就会工作。您正在做的是:

let rec a x =
    let rnd = System.Random()
    // ... Some code that calls rnd.Next() once, then recurses
每次递归时,都会创建一个新的
System.Random
实例并将其分配给
rnd
。这意味着您正在使用默认构造函数
System.Random
,并警告:

。。。通过调用默认构造函数连续创建的不同随机对象将具有相同的默认种子值,因此将生成相同的随机数集。通过使用单个随机对象生成所有随机数,可以避免此问题

您真正想要的是创建一个
Random
实例,然后重复使用其
.Next()
方法。一种方法是将
System.Random()
构造函数调用移到函数外部:

let theList = [Red;Green;Yellow;Purple;White;Black]
let rnd = System.Random()
let rec a x =    
    match x with 
    |0 -> []
    |_ -> (List.item(rnd.Next(6)) theList)::(a (x-1)) 
let theList = [Red;Green;Yellow;Purple;White;Black]
let doit x =
    let rnd = System.Random()
    let rec a x =
        match x with 
        |0 -> []
        |_ -> (List.item(rnd.Next(6)) theList)::(a (x-1))
    a x
另一种方法是,如果您不想将
rnd
名称公开给外部代码,可以将
a
转换为嵌套在外部函数中的“内部”函数(在下面的示例中,
doit
是外部函数):


这两种方法都会产生您期望的真正随机(伪随机)结果。

将您的
系统.random()
调用移出函数,它就会工作。您正在做的是:

let rec a x =
    let rnd = System.Random()
    // ... Some code that calls rnd.Next() once, then recurses
每次递归时,都会创建一个新的
System.Random
实例并将其分配给
rnd
。这意味着您正在使用默认构造函数
System.Random
,并警告:

。。。通过调用默认构造函数连续创建的不同随机对象将具有相同的默认种子值,因此将生成相同的随机数集。通过使用单个随机对象生成所有随机数,可以避免此问题

您真正想要的是创建一个
Random
实例,然后重复使用其
.Next()
方法。一种方法是将
System.Random()
构造函数调用移到函数外部:

let theList = [Red;Green;Yellow;Purple;White;Black]
let rnd = System.Random()
let rec a x =    
    match x with 
    |0 -> []
    |_ -> (List.item(rnd.Next(6)) theList)::(a (x-1)) 
let theList = [Red;Green;Yellow;Purple;White;Black]
let doit x =
    let rnd = System.Random()
    let rec a x =
        match x with 
        |0 -> []
        |_ -> (List.item(rnd.Next(6)) theList)::(a (x-1))
    a x
另一种方法是,如果您不想将
rnd
名称公开给外部代码,可以将
a
转换为嵌套在外部函数中的“内部”函数(在下面的示例中,
doit
是外部函数):


这两种方法都会产生您期望的真正随机(伪随机)结果。

将您的
System.random()
调用移出函数,它就会工作。我将写一个较长的答案来解释原因。如果将
System.Random()
调用移出函数,则可能会出现重复。我会写一个较长的答案来解释原因。可能是重复的,非常感谢!非常感谢你!