首先,我为非描述性标题道歉。因为我不知道实际发生了什么,所以我不能让它更具体。
现在我的问题。我已经为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)
现在,当我加载它时,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. 会发生。这里发生了什么?