El siguiente programa termina correctamente:¿Es el mapM en Haskell estricto? ¿Por qué este programa obtiene un desbordamiento de pila?
import System.Random
randomList = mapM (\_->getStdRandom (randomR (0, 50000::Int))) [0..5000]
main = do
randomInts <- randomList
print $ take 5 randomInts
de reproducción:
$ runhaskell test.hs
[26156,7258,29057,40002,26339]
Sin embargo, alimentándolo con una lista infinita, el programa nunca termina, y cuando se compila, finalmente, da un error de desbordamiento de pila!
import System.Random
randomList = mapM (\_->getStdRandom (randomR (0, 50000::Int))) [0..]
main = do
randomInts <- randomList
print $ take 5 randomInts
Correr,
$ ./test
Stack space overflow: current size 8388608 bytes.
Use `+RTS -Ksize -RTS' to increase it.
que espera que el programa para evaluar perezosamente getStdRandom
cada vez que cojo un elemento de la lista, terminando después de hacerlo 5 veces. ¿Por qué está tratando de evaluar toda la lista?
Gracias.
¿Existe alguna forma mejor de obtener una lista infinita de números aleatorios? Quiero pasar esta lista a una función pura.
EDIT: Un poco más de la lectura reveló que la función
randomList r = do g <- getStdGen
return $ randomRs r g
es lo que estaba buscando.
EDIT2: después de leer la respuesta de camccann, me di cuenta de que getStdGen
está recibiendo una nueva semilla en cada llamada. En su lugar, mejor usar esta función como un simple generador de lista aleatoria de una sola vez:
import System.Random
randomList :: Random a => a -> a -> IO [a]
randomList r g = do s <- newStdGen
return $ randomRs (r,g) s
main = do r <- randomList 0 (50::Int)
print $ take 5 r
Pero sigo sin entender por qué mi mapM
llamada no terminó. Evidentemente, no está relacionado con números aleatorios, pero puede que tenga algo que ver con mapM
.
Por ejemplo, he encontrado que el siguiente también no termina:
randomList = mapM (\_->return 0) [0..]
main = do
randomInts <- randomList
print $ take 50000 randomInts
lo que da? Por cierto, en mi humilde opinión, la función randomInts
anterior debe estar en System.Random
. Es extremadamente conveniente poder simplemente generar una lista aleatoria en la mónada IO y pasarla a una función pura cuando sea necesario, no veo por qué esto no debería estar en la biblioteca estándar.
Ah, y como una adición a mi respuesta: Puede escribir una versión más general de 'randomInts' como simplemente' \ r -> fmap (randomRs r) getStdGen'. Esto tiene el tipo '(Aleatorio a) => (a, a) -> IO [a]', en otras palabras, genera una lista de valores aleatorios en el rango dado para cualquier tipo que sea una instancia de 'Random'. –
Aún mejor, gracias. – Steve
Supongo que es por eso que mi función 'randomList' ni siquiera necesitaría estar en la lib estándar, si puede ser tan corta, pero no es obvio cómo escribir eso para una newb;) Así que todavía creo que debería ser allí por conveniencia ... – Steve