Come evitare il IO
dipende dal motivo per cui viene introdotto in primo luogo. Sebbene i generatori di numeri pseudo casuali siano intrinsecamente orientati allo stato, non c'è motivo di coinvolgere lo IO
.
Ho intenzione di indovinare e dire che stai usando newStdGen
o getStdGen
per ottenere il tuo PRNG iniziale. Se questo è il caso, non c'è modo di sfuggire completamente a IO
. Si potrebbe invece seminare il PRNG direttamente con mkStdGen
, tenendo presente che lo stesso seme produrrà la stessa sequenza numerica "casuale".
Più probabilmente, quello che vuoi fare è ottenere un PRNG all'interno di IO
, quindi passarlo come argomento a una funzione pura. L'intero oggetto verrà comunque incapsulato in IO
alla fine, ovviamente, ma i calcoli intermedi non ne avranno bisogno. Ecco un esempio veloce per darvi l'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'')
si potrebbe notare che il codice utilizzando il PRNG diventa piuttosto brutto a causa passando il valore corrente avanti e indietro in continuazione. È anche potenzialmente soggetto a errori, dal momento che sarebbe facile riutilizzare accidentalmente un vecchio valore. Come accennato in precedenza, l'uso dello stesso valore PRNG darà la stessa sequenza di numeri, che di solito non è ciò che si desidera. Entrambi i problemi sono un perfetto esempio di dove è logico utilizzare una monade State
- che qui è fuori discussione, ma potrebbe essere utile esaminarla successivamente.
fonte
2010-04-29 16:01:23
il momento in cui chiedi un campione, entri nella monade IO –