最初から始めましょう:
type Rand a = State StdGen a
この行は、それRand a
がタイプのタイプ同義語でありState
、その状態がによって与えられStdGen
、最終的な値がタイプであることを示していa
ます。これは、乱数の各要求間で乱数ジェネレーターの状態を格納するために使用されます。
のコードは、getRandom
do表記に変換できます。
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
の値を取ります(これは、覚えておいてください)の同義語です。で新しいジェネレータを作成し、にフィードします。この関数は、状態を無視して、型の戻り値を評価するだけです。r
Rand a
State StdGen a
mkStdGen n
evalState r
evalState
State 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
ます。