讓我們從頭開始:
type Rand a = State StdGen a
這行告訴你,Rand a
爲State
類型,其狀態由StdGen
給出,其最終的價值a
類型的類型代名詞。這將用於存儲每個隨機數請求之間的隨機數生成器的狀態。
爲getRandom
的代碼可以被轉換成做記號:
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
和Rand a
類型的值r
(其,請記住,僅僅是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]
中的實際值未使用(可以看出,因爲lambda函數以\_ -> ...
開頭)。該列表只是爲了擁有正確數量的元素。由於getRandom
返回一元值,因此我們使用mapM
來映射列表,這會導致狀態(即StdGen
)正確地通過對getRandom
的每個調用進行線程化。