2016-02-10 51 views
2

我想創建隨機序列,同時還經過randomGenerator mkStdGen哈斯克爾生成隨機序列,並通過發電機

我想出了以下內容,這似乎是工作,但我想知道是否有更好的/這樣做的適當方式?

genRandomSeq :: (RandomGen g, Random a) => Int -> (a,a) -> g -> ([a], g) 
genRandomSeq n rng g = 
    foldr (\_ (acc,g') -> (\(a,g'') -> (a:acc, g'')) (randomR rng g')) ([],g) [0..n] 


-- which is basically the same as 
genRandomSeq 0 rng g collected = (collected, g) 
genRandomSeq n rng g collected = 
    let (a,g') = randomR rng g in 
    genRandomSeq (n - 1) rng g' (a : collected) 


(xs,g) = genRandomSeq 5 ('a','z') (mkStdGen 10) 
(ys,g') = genRandomSeq 5 ('a','z') g 

zs = "my nice string: " ++ xs ++ ys :: String 

使用

*Main> genRandomSeq 5 ('a','z') (mkStdGen 10) 
("rrsvfx",1928412403 1780294415) 
*Main> zs 
"my nice string: rrsvfxyaygon" 
+1

備註:如果代碼已經有效並且您對評論感興趣,則可能是[codereview.SE]的候選人。 – Zeta

+0

不是。如果所有顯式傳球都困擾着你,你可以把它包裝在'State'中,那麼你的簽名看起來就像genRandomSeq ::(RandomGen g,Random a)=> Int - >(a,a) - > State g [a ]',如果你更喜歡這個,你會成爲法官。 – Cubic

+1

MonadRandom(和MonadCryptoRandom)是兩個包,可以讓生成器保持單態,並提供簡單的例程,形式爲「讓我隨機選擇X型」。 –

回答

1

我發現,通過種子明確是笨重的,惱人的,並導致組合性較差。我最喜歡的方法是使用自定義monad來生成隨機數。 The MonadRandom library是他們所有人的爺爺,我明白,但也有random-fu這是更有特色,但有點難開始。

使用MonadRandom和類似的工具,你的函數可以寫成這樣(沒有測試,但它應該是大約右):

import Control.Monad (replicateM) 
import Control.Monad.Random 

genRandomSeq :: Random a => Int -> (a,a) -> Rand g [a] 
getRandomSeq n range = replicateM n (getRandomR range) 

-- Your function is this, but in practice I might not bother writing it 
-- out as its own definition—basically, I'd work in the `Rand` monad as 
-- much as possible and only `runRand` where I really need to. 
runIt :: (RandomGen g, Random a) => Int -> (a,a) -> g -> ([a], g) 
runIt n range g = runRand (getRandomSeq n range) g 

如果你沒有研究過State單子,這將是一個好點爲你這樣做。 Rand monad只是一個專用的狀態monad,具有一些實用功能,可以更輕鬆地處理隨機生成。

練習:寫你自己的Rand類型,其FunctorApplicativeMonad實例和getRandomR操作的版本。