Ind*_*rek 17 random monads haskell
几天我一直在捣乱Haskell,偶然发现了一个问题.
我需要一个返回随机的整数列表的方法(Rand [[Int]]).
所以,我定义了一个类型:type Rand a = StdGen -> (a, StdGen).我能以某种方式生产Rand IO Integer和Rand [IO Integer]((returnR lst) :: StdGen -> ([IO Integer], StdGen)).任何提示如何生产Rand [[Int]]?
C. *_*ann 20
如何避免IO取决于它首先被引入的原因.虽然伪随机数生成器本质上是面向状态的,但没有理由IO需要涉及.
我会猜测并说你正在使用newStdGen或getStdGen获得你的初始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 有意义的完美示例- 这是在这里脱离主题,但您可能希望接下来进行调查.
如果你想得到一个无限的Integers 列表,你将会遇到问题,因为你不会得到一个StdGen值.你想在这里做的是split第StdGen一个,再将一半传递出来并"用尽"另一半来生成无限的整数列表.像这样的东西:
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]].