Cómo evitar el IO
depende de por qué se está introduciendo en primer lugar. Si bien los generadores de números pseudoaleatorios están inherentemente orientados al estado, no hay ninguna razón por la cual se deba involucrar IO
.
Voy a adivinar y decir que está usando newStdGen
o getStdGen
para obtener su PRNG inicial. Si ese es el caso, entonces no hay forma de escapar por completo IO
. En su lugar, puede sembrar el PRNG directamente con mkStdGen
, teniendo en cuenta que la misma semilla dará como resultado la misma secuencia numérica "aleatoria".
Lo más probable es que lo que quiere hacer es obtener un PRNG dentro de IO
, luego pase eso como un argumento a una función pura. Toda la cosa todavía estará envuelta en IO
al final, por supuesto, pero los cálculos intermedios no lo necesitarán. Aquí está un ejemplo rápido para darle la idea:
import System.Random
type Rand a = StdGen -> (a, StdGen)
getPRNG = do
rng <- newStdGen
let x = usePRNG rng
print x
usePRNG :: StdGen -> [[Int]]
usePRNG rng = let (x, rng') = randomInts 5 rng
(y, _) = randomInts 10 rng'
in [x, y]
randomInts :: Int -> Rand [Int]
randomInts 0 rng = ([], rng)
randomInts n rng = let (x, rng') = next rng
(xs, rng'') = randomInts (n - 1) rng'
in (x:xs, rng'')
usted podría notar que el código utilizando el PRNG se pone muy fea debido a que pasa el valor actual de ida y vuelta constante. También es potencialmente propenso a errores, ya que sería fácil reutilizar accidentalmente un valor anterior. Como se mencionó anteriormente, usar el mismo valor de PRNG dará la misma secuencia de números, que generalmente no es lo que desea. Ambos problemas son un ejemplo perfecto de dónde tiene sentido usar una mónada State
, que se está desviando del tema aquí, pero es posible que desee analizarla a continuación.
el momento en que pides una muestra, obtienes la mónada IO –