Haskell和随机数

Ind*_*rek 17 random monads haskell

几天我一直在捣乱Haskell,偶然发现了一个问题.

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

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

C. *_*ann 20

如何避免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'')
Run Code Online (Sandbox Code Playgroud)

您可能会注意到,使用PRNG的代码由于不断地来回传递当前值而变得相当丑陋.它也可能容易出错,因为很容易意外地重用旧值.如上所述,使用相同的PRNG值将给出相同的数字序列,这通常不是您想要的.这两个问题都是使用Statemonad 有意义的完美示例- 这是在这里脱离主题,但您可能希望接下来进行调查.


luq*_*qui 11

您正在重建Hackage上的MonadRandom.如果这不仅仅是一个实验,看看你是否可以这样做,你可能想要使用该库.


yat*_*975 6

如果你想得到一个无限Integers 列表,你将会遇到问题,因为你不会得到一个StdGen值.你想在这里做的是splitStdGen一个,再将一半传递出来并"用尽"另一半来生成无限的整数列表.像这样的东西:

infiniteRandomInts :: Rand [Int]
infiniteRandomInts g = (ints, g2) where
    (g1,g2) = split g
    ints = randoms g1
Run Code Online (Sandbox Code Playgroud)

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