2016-11-07 71 views
1

我有這個功能,選擇4種隨機顏色並製作一個列表。至少我希望它太:F#System.Random在做一個有趣的東西的遞歸函數

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循環中使用隨機方法則沒有問題。

有人可以向我解釋這裏發生了什麼?

+3

將你的System.Random()調用移出該函數,它將起作用。我會寫一個更長的答案來解釋爲什麼。 – rmunn

+1

[在F#中獲取隨機數]的可能重複(http://stackoverflow.com/questions/37898225/get-random-numbers-in-f) –

回答

4

將您的System.Random()調用移出該函數,它將起作用。你在做什麼是:

let rec a x = 
    let rnd = System.Random() 
    // ... Some code that calls rnd.Next() once, then recurses 

你遞歸每一次,你要創建一個新的System.Random實例並將其分配給rnd。這意味着,你正在使用的System.Random默認的構造函數,its documentation警告說:

...正在緊密相繼通過的默認構造函數的調用創建將具有相同的默認種子值不同的隨機對象和,因此,將產生相同的隨機數組。通過使用單個隨機對象來生成所有隨機數,可以避免此問題。

你真正想要的是創建一個單一的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)) 

另一種方式,如果你不想暴露rnd名外部的代碼,將轉a到「內」該嵌套的外部函數內部'S(在下面的例子中,doit是外功能)功能:

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 

這兩個應該產生真正隨機的(當然,僞隨機),結果你期待。

+0

非常感謝! – Nulle