18

几天来我一直在搞乱Haskell,偶然发现了一个问题。

我需要一个返回随机整数列表的方法( Rand [[Int]] )。

所以,我定义了一个类型:type Rand a = StdGen -> (a, StdGen). 我能够以某种方式产生Rand IO IntegerRand [IO Integer](returnR lst) :: StdGen -> ([IO Integer], StdGen))。任何提示如何生产Rand [[Int]]

4

4 回答 4

21

如何避免IO取决于首先引入它的原因。虽然伪随机数生成器本质上是面向状态的,但没有理由IO需要涉及。

我将猜测并说您正在使用newStdGengetStdGen获取您的初始 PRNG。如果真是这样,那就没有办法彻底逃脱了IO。您可以改为直接使用 为 PRNG 播种,请mkStdGen记住,相同的种子将产生相同的“随机”数字序列。

更有可能的是,您想要做的是在内部获取 PRNG IO,然后将其作为参数传递给纯函数。当然,整个事情最终仍然会被包裹起来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 值会给出相同的数字序列,这通常不是您想要的。这两个问题都是一个完美的例子,说明使用 monad 是有意义的State——这在这里离题了,但你可能想接下来研究它。

于 2010-04-29T16:01:23.510 回答
11

您正在在Hackage上重新创建 MonadRandom。如果这不仅仅是一个试验,看看你是否能做到,你可能想改用那个库。

于 2010-04-29T23:17:34.593 回答
6

如果你想获得一个无限的 s 列表,Integer你会遇到问题,因为你永远不会得到一个StdGen值。您在这里要做的是splitStdGen一个,再次传递一半并“用完”另一半以生成无限的整数列表。像这样的东西:

infiniteRandomInts :: Rand [Int]
infiniteRandomInts g = (ints, g2) where
    (g1,g2) = split g
    ints = randoms g1

但是,如果您然后重复这种方法以获得 s 的无限矩阵Integer(您似乎想要,通过使用Rand [[Int]]),您可能会遇到统计性质的问题:我不知道如何StdGen处理重复splitting。也许另一种实现RandomGen可能会更好,或者您可以尝试使用某种对角线步行将 a[Int]变成 a [[Int]]

于 2010-04-29T20:47:33.710 回答
3

使用一元符号,你应该能够写出类似的东西

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

关于单子计算本身,看看这篇文章。请注意,随机生成器是纯粹的,你不应该IO仅仅为了这个目的而需要任何生成器。

于 2010-04-29T15:36:07.397 回答