Haskell and random numbers

后端 未结 4 958
耶瑟儿~
耶瑟儿~ 2021-02-02 13:31

I\'ve been messing with Haskell few days and stumbled into a problem.

I need a method that returns a random list of integers ( Rand [[Int]] ).

So, I defined a ty

相关标签:
4条回答
  • 2021-02-02 13:55

    How to avoid the IO depends on why it's being introduced in the first place. While pseudo-random number generators are inherently state-oriented, there's no reason IO needs to be involved.

    I'm going to take a guess and say that you're using newStdGen or getStdGen to get your initial PRNG. If that's the case, then there's no way to completely escape IO. You could instead seed the PRNG directly with mkStdGen, keeping in mind that the same seed will result in the same "random" number sequence.

    More likely, what you want to do is get a PRNG inside IO, then pass that as an argument to a pure function. The entire thing will still be wrapped in IO at the end, of course, but the intermediate computations won't need it. Here's a quick example to give you the idea:

    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'')
    

    You might notice that the code using the PRNG gets pretty ugly due to passing the current value back and forth constantly. It's also potentially error prone, since it'd be easy to accidentally reuse an old value. As mentioned above, using the same PRNG value will give the same sequence of numbers, which is usually not what you want. Both problems are a perfect example of where it makes sense to use a State monad--which is getting off topic here, but you may want to look into it next.

    0 讨论(0)
  • 2021-02-02 14:00

    If you want to get an infinite list of Integers you're going to run into problems as you won't ever get a StdGen value back out. What you want to do here is split the StdGen first, pass one half out again and 'use up' the other half to generate an infinite list of integers. Something like this:

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

    However, if you then repeat this approach to get an infinite matrix of Integers (which you seem to want, by using Rand [[Int]]), you might run into problems of a statistical nature: I don't know how well StdGen deals with repeated splitting. Maybe another implementation of RandomGen might be better, or you could try to use some sort of diagonal walk to turn a [Int] into a [[Int]].

    0 讨论(0)
  • 2021-02-02 14:08

    Using monadic notation, you should be able to write something like

    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) }
    

    And with this

    randomInts :: Rand [Int]
    randomInts = randomList yourRandomInteger
    
    randomLists :: Rand [[Int]]
    randomLists = randomList randomInts
    

    Concerning the monadic computations itself, take a look at this article. Note that random generators are pure, you shouldn't need any IO just for this purpose.

    0 讨论(0)
  • 2021-02-02 14:12

    You are recreating MonadRandom on Hackage. If this is more than just an experiment to see if you can do it, you might want to use that library instead.

    0 讨论(0)
提交回复
热议问题