首先,我为非描述性标题道歉。由于我不知道实际上发生了什么,我无法让它更具体。
现在提出我的问题。我已针对99 Haskell problems的问题23实施了以下代码段,该问题应从列表中随机选择n
个项目:
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)
现在,当我在ghci
中加载它时,这适用于有效参数:
*Main> rndSelectIO' "asdf" 2 >>= putStrLn
af
然而,当我使用超出范围的索引时会发生奇怪的事情:
*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
正如您所看到的,以下2(对我来说)意外事情发生了:
我怀疑1.与懒惰的评价有关,但我完全不知道为什么2.发生。这里发生了什么?
答案 0 :(得分:13)
getStdRandom
函数基本上在全局变量中查找StdGen
值,在其上运行一些函数,将新种子放回全局变量中,并将结果返回给调用者。 / p>
如果有问题的函数返回错误,则该错误将被放入全局变量中。现在,所有使用此全局变量的尝试都将引发异常。 (我告诉你的全局变量是邪恶的!;-)
)
尝试亲自手动调用getStdGen
。它将打印出当前的随机种子,或抛出异常。如果它抛出异常......就是你的问题。
我相信您可以使用setStdGen
重置该内容。