First of all, my apologies for the non-descriptive title. Since I have no idea what's actually going on I can't really make it any more specific.
Now for my question. I have implemented the following snippet for problem 23 of the 99 Haskell problems, which should randomly select n
items from a list:
rndSelect' :: RandomGen g => [a] -> Int -> g -> ([a], g)
rndSelect' _ 0 gen = ([], gen)
rndSelect' [] _ _ = error "Number of items requested is larger than list"
rndSelect' xs n gen = ((xs !! i) : rest, gen'')
where (i, gen') = randomR (0, length xs - 1) gen
(rest, gen'') = (rndSelect' (removeAt xs i) (n - 1) gen')
rndSelectIO' :: [a] -> Int -> IO [a]
rndSelectIO' xs n = getStdRandom $ rndSelect' xs n
removeAt :: [a] -> Int -> [a]
removeAt xs n
| length xs <= n || n < 0 = error "Index out of bounds"
| otherwise = let (ys, zs) = splitAt n xs
in ys ++ (tail zs)
Now when I load this in ghci
this works correctly for valid arguments:
*Main> rndSelectIO' "asdf" 2 >>= putStrLn
af
However, strange things happen when I use an index that is out of bounds:
*Main> rndSelectIO' "asdf" 5 >>= putStrLn
dfas*** Exception: Number of items requested is larger than list
*Main> rndSelectIO' "asdf" 2 >>= putStrLn
*** Exception: Number of items requested is larger than list
As you can see, the following 2 (for me) unexpected things happen:
I suspect that 1. has to do with lazy evaluation, but I have absolutely no clue why 2. happens. What's going on here?
The getStdRandom
function basically looks up a StdGen
value in a global variable, runs some function on it, puts the new seed back into the global variable, and returns the result to the caller.
If the function in question returns with an error, that error gets put into the global variable. Now all attempts to use this global variable will throw an exception. (I told you global variables are evil! ;-)
)
Try calling getStdGen
manually yourself. It will either print out the current random seed, or throw an exception. If it throws an exception... there's your problem.
I believe you can use setStdGen
to reset the thing.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With