Trying to solve problem 23 of 99 Haskell Problems.
And I wrote this
rnd_select :: (Eq a) => [a] -> Int -> [a]
rnd_select [] _ = []
rnd_select _ 0 = []
rnd_select ys n =
let
(rnd_index, gen) = randomR (1, length ys) (mkStdGen 200)
(x, xs) = removeAt rnd_index ys
in x : rnd_select xs (n-1)
which works but I dont want use mkStdGen but use
newStdGen or getStdGen
instead.
I have seen the solutions to the problem but I want to understand how should I fix this code to do that and if its not possible why not because intuitively it feels like it should work but it doesn’t.
Remember that Haskell functions are pure; they must always return the same result given the same input. You could make your function return
IO [a]instead, which would let you callnewStdGen, but a better way is to keep your code pure by taking the random number generator as an additional argument to your function and also returning the new generator afterwards:Now you can use it with, e.g.
getStdRandom :: (StdGen -> (a, StdGen)) -> IO alike this.Passing the generators around manually can be somewhat tedious, though. One way of making this neater is to use the MonadRandom package.
Since
IOis an instance ofMonadRandom, you can use this directly as anIOaction.or you can use
evalRandto run this in a pure monad, providing your own random number generator so you can get repeatable results (good for debugging / testing).