miRandom =
do
newStdGen
g<-getStdGen
let
a = 0::Int
b = 20::Int
x = randomR (a, b) g
print x
Que imprime por pantalla:
(17,1295529924 1123184626)
:: IO ()
La función miRandom imprime por pantalla la representación de la variable x que es del tipo (Int, StdGen). Vamos, el 17 es el número aleatorio entre 0 y 20, que son las variables a y b, y los otros dos números largos y extraños que forman el segundo campo de la tupla son un nuevo StdGen, que explicaremos después.
- StdGen
- Tipo de dato que representa un generador de números aleatorios. Necesario para todas las funciones encargadas de la generación del número.
- getStdGen
- Función que devuelve el generador de números aleatorios por defecto.
- newStdGen:
- Función que "actualiza" el generador de números aleatorios por defecto.
- randomR
- ::(Random a, RandomGen b) => (a,a) -> b -> (a,b)
Recibe una tupla con los límites entre los que queremos sacar el elemento aleatorio y, como segundo un generador de números aleatorios, siempre del tipo StdGen.
En realidad, por defecto, pueden sacarse elementos aleatorios de los siguientes tipos de datos: Bool, Int, Integer, Char, Float, Double
Importante: clases genéricas (como Num) NO funcionarán en esta función.
miRandom2 =
do
newStdGen
g<-getStdGen
let
a = 0::Int
b = 20::Int
x = randomR (a, b) g
y = randomR (a, b) g
print x
print y
y la ejecutamos, obtenemos esto:
(12,1295689980 1326707213)
(12,1295689980 1326707213)
:: IO ()
Es decir, el número aleatorio generado (el 12) es el mismo para ambas variables. ¿Casualidad? Podría ser. Pero si ejecutamos la función infinitas veces esas infinitas veces y las siguientes, los números aleatorios generados por randomR serán siempre los mismos para x e y. ¿Por qué? Porque el generador de números aleatorios siempre es el mismo, g y a partir de él siempre se generan los mismos números.
Solución: ¿Recuerdas que randomR devuelve una tupla en la que el primer miembro es el elemento aleatorio y el segundo dos números grandes y extraños? Pues ese segundo miembro es un nuevo elemento de tipo StdGen, distinto al original recibido por la función, y que utilizaremos para encontrar el siguiente número aleatorio. Entonces:
miRandom3 =
do
newStdGen
g<-getStdGen
let
a = 0::Int
b = 20::Int
x = randomR (a, b) g
y = randomR (a, b) (snd x)
print x
print y
Que tiene como salida:
(14,1994861249 30671636)
(16,413980776 402357293)
:: IO ()
Para terminar, recalcar que el uso de newStdGen es necesario para actualizar el generador de números aleatorios por defecto.
Si no lo hiciéramos, en cada una de las ejecuciones de miRandom3 los números aleatorios serían los mismos. Es decir, si en la primera ejecución fst x fuera 13 y fst y fuera 15, en las sucesivas ejecuciones de miRandom3, fst x y fst y continuarían valiendo 13 y 15, porque ambas generaciones, al no haber sido invocada newStdGen, partirían del mismo StdGen por defecto.