最初から始めましょう:
type Rand a = State StdGen a
この行は、それRand aがタイプのタイプ同義語でありState、その状態がによって与えられStdGen、最終的な値がタイプであることを示していaます。これは、乱数の各要求間で乱数ジェネレーターの状態を格納するために使用されます。
のコードは、getRandomdo表記に変換できます。
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
このrunRand関数は、初期シードとタイプnの値を取ります(これは、覚えておいてください)の同義語です。で新しいジェネレータを作成し、にフィードします。この関数は、状態を無視して、型の戻り値を評価するだけです。rRand aState StdGen amkStdGen nevalState revalStateState s a
ここでも、表記にrunRandIO変換できます。do
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
最後に、生成するランダム値の数を表す数値をgetRandoms取ります。nリストを作成し、リスト[1..n]に適用getRandomします。の実際の値[1..n]は使用されないことに注意してください(ラムダ関数はで始まるためわかります\_ -> ...)。リストは、正しい数の要素を持つものを持っているだけです。getRandomはモナディック値を返すため、を使用しmapMてリストをマップします。これにより、状態(つまりStdGen)がへの各呼び出しに正しくスレッド化されgetRandomます。