I want to generate N numbers using System.Random.next function. I implemented a function which takes a StdGen and a list of numbers and returns new generator and updated list of numbers:
import System.Random
getRandNum :: StdGen -> [Int] -> (StdGen, [Int])
getRandNum gen nums = (newGen, newNums)
where
(randNum, newGen) = next gen
newNums = nums ++ [randNum]
Then I can use it in the following way:
λ: getRandNum (mkStdGen 1) []
(80028 40692,[39336])
But I have a problem with executing that function N times to get the list of random numbers. How can I chain it in a proper way?
I also tried the recursive way -- it works, but I'm sure this solution is far from elegant:
randomnumbers_ :: Int -> StdGen -> (StdGen, [Int])
randomnumbers_ 0 gen = (gen, [])
randomnumbers_ 1 gen = (newGen, [randNum])
where
(randNum, newGen) = next gen
randomnumbers_ n gen = (newGen2, nums ++ nums2)
where
(newGen, nums) = randomnumbers_ 1 gen
(newGen2, nums2) = randomnumbers_ (n - 1) newGen
randomnumbers :: Int -> Int -> [Int]
randomnumbers n seed = snd $ randomnumbers_ n generator
where
generator = mkStdGen seed
By the way yes, I know that it can be implemented using the State monad and I know how to do it.
The way to chain it is to implement it in such a way that you don't need to do it, i.e. so that it does the chaining by itself.
There's an inherent contradiction in your code anyway, you call it
getRandNum, singular, and it indeed gets just one number, but the type is[Int].So then we resolve all this, with a minimal edit to your code, as
This kind of scheme is typical for Haskell, building lists in the top-down fashion using what's known as guarded recursion, i.e. with recursion guarded by a lazy data constructor (in this case,
:). Lists built with repeated appending of singletons as you do are very inefficient, have quadratic behavior when accessed.Having
newGensafely hidden inside, encapsulated, is an additional bonus. You don't want it exposed, what would be the use? Restarting the randoms generating sequence from the middle would just recreate the same sequence of numbers anyway.And of course you can take as many of the numbers off that list as you wish, with
take n.