Cominciamo dall'inizio:
type Rand a = State StdGen a
Questa linea vi dice che Rand a
è un tipo sinonimo di un tipo State
, il cui stato è data da StdGen
e il cui valore finale è di tipo a
. Questo sarà usato per memorizzare lo stato del generatore di numeri casuali tra ogni richiesta di un numero casuale.
Il codice per getRandom
può essere convertito in notazione fare:
getRandom :: (Random a) => Rand a
getRandom = do
r <- get -- get the current state of the generator
let (a,g) = random r in do -- call the function random :: StdGen -> (a, StdGen)
put g -- store the new state of the generator
return a -- return the random number that was generated
La funzione runRand
prende un seme iniziale n
e un valore r
di tipo Rand a
(che, ricordiamo, è solo un sinonimo di State StdGen a
). Crea un nuovo generatore con mkStdGen n
e lo invia a evalState r
. La funzione evalState
valuta solo il valore restituito di un tipo State s a
, ignorando lo stato.
Anche in questo caso, siamo in grado di convertire in runRandIO
do
notazione:
runRandIO :: Rand a -> IO a
runRandIO r = do
rnd <- randomIO -- generate a new random number using randomIO
return (runRand rnd r) -- use that number as the initial seed for runRand
Infine, getRandoms
prende un numero n
che rappresenta il numero di valori casuali che si desidera generare. Costruisce un elenco [1..n]
e applica getRandom
all'elenco. Si noti che i valori effettivi in [1..n]
non vengono utilizzati (lo si può sapere perché la funzione lambda inizia con \_ -> ...
). L'elenco è solo lì per avere qualcosa con il numero corretto di elementi. Poiché getRandom
restituisce un valore monadico, usiamo mapM
mappare sulla lista, che causa lo stato (cioè StdGen
) da filettare correttamente attraverso ciascuna delle chiamate getRandom
.
fonte
2012-06-15 09:14:24