2011-08-13 14 views
5

Sto cercando di usare F # per generare un elenco di triple casuali -> due numeri casuali e la loro somma:generazione casuale nella lista 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 

che può essere chiamato così e funziona bene (dà sempre un nuovo numero casuale) (quando si utilizza F # interattivo)

foo 0 50 

quando si tenta di generare un elenco di triple casuali come questo

List.init 100 (fun index -> foo 0 50) 

Vorrei che questo fosse un elenco di 100 tripli randomizzati, ma invece vengono tutti con lo stesso valore. Posso vedere che la funzione non dipende dall'indice e quindi non ha bisogno di ricalcolare, ma non sono sicuro di come aggirare (ho provato a introdurre l'indice come una variabile fittizia inutilizzata, ho anche provato a introdurre l'indice come seme casuale, ma non aiutato)

risposta

14

Si presume che il motivo per cui il codice non funzioni come si vuole è che il compilatore applica erroneamente una sorta di eliminazione di sottoespressione comune, che fa sì che foo 0 50 venga valutato solo una volta . Questo non è il caso. Il compilatore sa molto bene che le funzioni possono essere impure e non eseguiranno ottimizzazioni che si interromperanno con il codice impuro (a meno che il codice specifico che viene ottimizzato possa essere dimostrato puro). Quindi non devi preoccuparti di far pensare al compilatore che stai usando l'argomento.

Il problema non è che foo 0 50 viene chiamato una sola volta: è infatti chiamato 100 volte come si desidera. Il problema è che restituisce lo stesso valore ogni 100 volte chiamato.

Ma perché dovrebbe farlo quando restituisce valori diversi quando lo si verifica manualmente?

Perché si crea un nuovo oggetto casuale ogni volta che si chiama foo. Poiché non si fornisce un valore di inizializzazione a quell'oggetto casuale, esso verrà seminato con l'ora di sistema corrente. Quindi, se chiami la funzione più volte con un po 'di tempo che passa in mezzo, restituirà valori diversi ogni volta. Tuttavia, se la chiami 100 volte in così poco tempo che l'ora del sistema non cambia in mezzo, riceverai lo stesso valore 100 volte.

Quindi la soluzione al tuo problema è riutilizzare lo stesso oggetto casuale, invece di crearne uno nuovo ogni volta che viene chiamato foo.

+0

molte grazie, funziona! –

3

Per completare la risposta sepp2k con un po 'di codice:

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

Prova a modificare. Sarà riutilizzare lo stesso oggetto casuale senza dover tenere un giro per il vostro scopo principale:

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 

Si noti inoltre che il prossimo non è threadsafe, quindi se avete intenzione di utilizzare foo da diversi thread è necessario aggiungere un po 'di blocco per Il prossimo.