为什么GHCI在出错后会陷入错误状态?

Tid*_*ddo 11 monads haskell io-monad

首先,我为非描述性标题道歉.由于我不知道实际发生了什么,所以我无法让它更具体.

现在我的问题.我已经为99个Haskell问题中的问题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)
Run Code Online (Sandbox Code Playgroud)

现在当我加载它时,ghci这适用于有效的参数:

*Main> rndSelectIO' "asdf" 2 >>= putStrLn 
af
Run Code Online (Sandbox Code Playgroud)

但是,当我使用超出范围的索引时会发生奇怪的事情:

*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
Run Code Online (Sandbox Code Playgroud)

如您所见,以下2(对我来说)意外事情发生:

  1. 它不是直接给出错误,而是首先打印输入的排列.
  2. 在它发出一次错误之后,它将不再执行.

我怀疑1.与懒惰评估有关,但我完全不知道为什么2.发生.这里发生了什么?

Mat*_*hid 13

getStdRandom函数基本上StdGen在全局变量中查找一个值,在其上运行一些函数,将新种子放回全局变量中,并将结果返回给调用者.

如果有问题的函数返回错误,则该错误将被放入全局变量中.现在,所有使用此全局变量的尝试都将引发异常.(我告诉你全局变量是邪恶的!;-))

尝试getStdGen自己手动调用.它将打印出当前的随机种子,或抛出异常.如果它抛出异常......那就是你的问题.

我相信你可以setStdGen用来重置这个东西.