几天来我一直在捣乱Haskell并且偶然发现了一个问题。
我需要一个返回随机整数列表的方法(Rand [[Int]])。
所以,我定义了一个类型:type Rand a = StdGen -> (a, StdGen)
。
我能以某种方式生成Rand IO Integer
和Rand [IO Integer]
((returnR lst) :: StdGen -> ([IO Integer], StdGen)
)。有关如何制作Rand [[Int]]
的任何提示?
答案 0 :(得分:20)
如何避免IO
取决于它首先被引入的原因。虽然伪随机数生成器本质上是面向状态的,但没有理由IO
需要参与。
我会猜测并说您正在使用newStdGen
或getStdGen
来获取您的初始PRNG。如果是这种情况,那么就无法完全逃脱IO
。您可以使用mkStdGen
直接为PRNG播种,请记住,相同的种子将导致相同的“随机”数字序列。
更有可能的是,你要做的是在IO
内获得PRNG,然后将其作为参数传递给纯函数。当然,整个事情仍然会被包裹在IO
中,但中间计算不需要它。这是一个快速举例说明:
import System.Random
type Rand a = StdGen -> (a, StdGen)
getPRNG = do
rng <- newStdGen
let x = usePRNG rng
print x
usePRNG :: StdGen -> [[Int]]
usePRNG rng = let (x, rng') = randomInts 5 rng
(y, _) = randomInts 10 rng'
in [x, y]
randomInts :: Int -> Rand [Int]
randomInts 0 rng = ([], rng)
randomInts n rng = let (x, rng') = next rng
(xs, rng'') = randomInts (n - 1) rng'
in (x:xs, rng'')
您可能会注意到,使用PRNG的代码由于不断地来回传递当前值而变得相当丑陋。它也可能容易出错,因为很容易意外地重用旧值。如上所述,使用相同的PRNG值将给出相同的数字序列,这通常不是您想要的。这两个问题都是一个完美的例子,说明使用State
monad是有意义的 - 这是在这里脱离主题,但你可能想要接下来查看它。
答案 1 :(得分:11)
您正在Hackage上重新创建MonadRandom。如果这不仅仅是一个实验,看看你是否可以这样做,你可能想要使用该库。
答案 2 :(得分:6)
如果你想获得一个无限的Integer
列表,你会遇到问题,因为你不会得到StdGen
值。你想在这里做的是split
StdGen
首先,再将一半传递出来,然后“用完”另一半来生成无限的整数列表。像这样:
infiniteRandomInts :: Rand [Int]
infiniteRandomInts g = (ints, g2) where
(g1,g2) = split g
ints = randoms g1
但是,如果你重复这种方法来获得Integer
s的无限矩阵(你似乎想要使用Rand [[Int]]
),你可能遇到统计性的问题:我不知道StdGen
如何处理重复的split
ting。也许RandomGen
的另一个实现可能会更好,或者您可以尝试使用某种对角线步行将[Int]
转换为[[Int]]
。
答案 3 :(得分:3)
使用monadic表示法,您应该能够编写类似
的内容randomList gen = do
randomLength <- yourRandomInteger
loop gen (randomLength + 1)
where
loop gen 1 = gen
loop gen n = do { x <- gen; xs <- loop gen (n - 1); return (x:xs) }
用这个
randomInts :: Rand [Int]
randomInts = randomList yourRandomInteger
randomLists :: Rand [[Int]]
randomLists = randomList randomInts
关于monadic计算本身,请看this article。请注意,随机生成器是纯粹的,您不应该只为此目的使用任何IO
。