2011-08-13 17 views
5

Estoy tratando de usar F # para generar una lista de triples al azar -> dos números al azar y su suma:generación aleatoria en la 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 

que se puede llamar así y funciona bien (siempre da una nuevo número aleatorio) (cuando se utiliza F # interactiva)

foo 0 50 

cuando se trata de generar una lista de triples al azar como esto

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

Me gustaría que esta sea una lista de 100 triples aleatorizados, pero todos salen con el mismo valor. Puedo ver que la función no depende del índice y, por lo tanto, no es necesario recalcular, pero no estoy seguro de cómo solucionarlo (traté de introducir el índice como una variable ficticia no utilizada, también intenté introducir el índice como una al azar, pero ninguno ayudó)

Respuesta

14

Suponiendo que el código no funciona como usted quiere es que el compilador aplica erróneamente algún tipo de eliminación de subexpresiones común, lo que hace que foo 0 50 se evalúe una sola vez . Este no es el caso. El compilador sabe muy bien que las funciones pueden ser impuras y no realizarán optimizaciones que se rompan con el código impuro (a menos que se pueda probar que el código específico que se está optimizando es puro). Entonces, no tiene que preocuparse por hacer que el compilador piense que está usando el argumento.

El problema no es que foo 0 50 se invoque solo una vez; de hecho, se llama 100 veces como desee. El problema es que devuelve el mismo valor cada una de las 100 veces que se llama.

¿Pero por qué haría eso cuando devuelve valores diferentes cuando lo prueba manualmente?

Porque crea un nuevo objeto aleatorio cada vez que llama al foo. Como no proporciona un valor inicial para ese objeto aleatorio, se sembrará con la hora actual del sistema. Por lo tanto, si llama a la función varias veces con un intervalo de tiempo intermedio, devolverá valores diferentes cada vez. Sin embargo, si lo llama 100 veces en un tiempo tan corto que la hora del sistema no cambia entre medio, obtendrá el mismo valor 100 veces.

Así que la solución a su problema es reutilizar el mismo objeto aleatorio, en lugar de crear uno nuevo cada vez que se llama a foo.

+0

muchas gracias, eso funciona! –

3

Para complementar la respuesta sepp2k con algo de código:

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

probar este lugar. Se volverá a utilizar el mismo objeto al azar sin tener que mantener a uno en torno a su ámbito principal:

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 

También tenga en cuenta que el próximo no se multihebra por lo que si se va a utilizar foo de varios hilos que necesita para añadir un poco de bloqueo para Siguiente.

Cuestiones relacionadas