2011-08-13 59 views
5

我想使用F#生成隨機三元組的列表 - >兩個隨機數和他們的總和:隨機生成到fsharp列表

let foo minNum maxNum = 
    let rnd = System.Random() 
    let first = rnd.Next(minNum, maxNum) 
    let second = rnd.Next(minNum, maxNum) 
    let third = first + second 
    first, second, third 

可以這樣調用和行之有效的(總是給人一種新的隨機數)(使用F#交互)時

foo 0 50 

當試圖產生這樣

List.init 100 (fun index -> foo 0 50) 
隨機三元組的列表

我想這是100個隨機化三元組的列表,但他們都拿出相同的價值。我可以看到函數不依賴於索引,因此不需要重新計算,但我不知道如何解決它(我嘗試將索引作爲未使用的虛擬變量引入,也嘗試將索引作爲隨機種子,但都沒有幫助)

回答

14

你假設你的代碼不能像你想要的那樣工作的原因是編譯器錯誤地應用某種常見的子表達式消除,這會導致foo 0 50僅被評估一次。不是這種情況。編譯器非常清楚函數可能不純,並且不會執行會破壞不純代碼的優化(除非被優化的特定代碼可以被證明是純的)。所以你不必擔心讓編譯器認爲你在​​使用參數。

問題不是foo 0 50只被調用一次 - 它的確被稱爲100次就像你想要的。問題在於它每次調用100次時都會返回相同的值。

但是,如果手動測試時返回不同的值,爲什麼會這樣呢?

因爲每次撥打foo時都會創建一個新的Random對象。由於您沒有爲該隨機對象提供種子值,因此將使用當前系統時間播種。因此,如果您在一段時間之後通過多次調用函數,則每次都會返回不同的值。但是,如果在如此短的時間內將系統時間調整爲100次,則系統時間不會再發生變化,您將獲得相同的值100次。

因此,您的問題的解決方案是重複使用相同的隨機對象,而不是每次調用foo時創建一個新對象。

+0

非常感謝,該作品! –

3

要使用一些代碼補sepp2k答案:

let rnd = System.Random() 

let foo minNum maxNum = 
    let first = rnd.Next(minNum, maxNum) 
    let second = rnd.Next(minNum, maxNum) 
    let third = first + second 
    first, second, third 
11

試試這個。它會重複使用相同的隨機對象,而您不必在你的範圍主要圍繞保持一個:

let foo = 
    let rnd = System.Random() 
    fun minNum maxNum -> 
     let first = rnd.Next(minNum, maxNum) 
     let second = rnd.Next(minNum, maxNum) 
     let third = first + second 
     first, second, third 

還要注意,接下來是不是線程安全的,所以如果你打算使用FOO從多個線程,你需要一些鎖定添加到下一個。