我想在传递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"
答案 0 :(得分: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
monad,那么这对你来说是个好点。 Rand
monad只是一个专门的状态monad,具有一些实用函数,可以更容易地使用随机生成。
练习:编写您自己的Rand
类型版本,Functor
,Applicative
和Monad
个实例以及{{1}操作。