Как правило, с Haskell лучше работает, чтобы максимизировать количество функционального кода за счет нефункционального (IO или случайного) кода.
В вашей ситуации ваш «максимальный» функциональный компонент - это не removeItem
, а скорее версия shuffleList
, которая принимает входной список и (как упомянул Уилл Несс) детерминированный c целое число позиция . Функция списка splitAt :: Int -> [a] -> ([a], [a]) может пригодиться здесь. Например:
funcShuffleList :: Int -> [a] -> [a]
funcShuffleList _ [] = []
funcShuffleList pos ls =
if (pos <=0) || (length(take (pos+1) ls) < (pos+1))
then ls -- pos is zero or out of bounds, so leave list unchanged
else let (left,right) = splitAt pos ls
in (head right) : (left ++ (tail right))
Тестирование:
λ>
λ> funcShuffleList 4 [0,1,2,3,4,5,6,7,8,9]
[4,0,1,2,3,5,6,7,8,9]
λ>
λ> funcShuffleList 5 "@ABCDEFGH"
"E@ABCDFGH"
λ>
Как только вы это получите, вы можете ввести вопросы случайности проще. И вам не нужно явно привлекать IO, как это делает любая монада, дружественная к случайности:
shuffleList :: MonadRandom mr => [a] -> mr [a]
shuffleList [] = return []
shuffleList ls =
do
let maxPos = (length ls) - 1
pos <- getRandomR (0, maxPos)
return (funcShuffleList pos ls)
... IO - это всего лишь один экземпляр MonadRandom .
Вы можете запустить код с помощью генератора случайных чисел по умолчанию, размещенного в IO:
main = do
let inpList = [0,1,2,3,4,5,6,7,8]::[Integer]
putStrLn $ "inpList = " ++ (show inpList)
-- mr automatically instantiated to IO:
outList1 <- shuffleList inpList
putStrLn $ "outList1 = " ++ (show outList1)
outList2 <- shuffleList outList1
putStrLn $ "outList2 = " ++ (show outList2)
Вывод программы:
$ pickShuffle
inpList = [0,1,2,3,4,5,6,7,8]
outList1 = [6,0,1,2,3,4,5,7,8]
outList2 = [8,6,0,1,2,3,4,5,7]
$
$ pickShuffle
inpList = [0,1,2,3,4,5,6,7,8]
outList1 = [4,0,1,2,3,5,6,7,8]
outList2 = [2,4,0,1,3,5,6,7,8]
$
Вывод здесь не воспроизводится, так как генератор по умолчанию засеян по времени запуска в наносекундах.
Если вам нужна полная случайная перестановка, вы можете посмотреть здесь и там - алгоритм Кнута или Фишера-Йейтса .