随机化一个Haskell列表

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了随机化一个Haskell列表相关的知识,希望对你有一定的参考价值。

我想编写一个Haskell程序,它将“随机化”列表中的元素:

import System.Random (getStdGen, randomRIO)
import Data.List (permutations)

rndElem :: [a] -> IO a
rndElem xs = do
  index <- randomRIO (0, length xs - 2)
  return $ xs !! index

rndPermutation :: [a] -> IO [a]
rndPermutation xs = rndElem . permutations $ xs

但是,运行它似乎并不完全随机化列表。由于某些原因,它仅使每个其他元素随机化,例如, [1,2,3,4,5,6] - > [5,2,1,4,3,6]。这个算法的每次运行都将奇数索引(2,4,6)元素保持在同一个位置。在上述算法的索引中是否存在任何逻辑错误?

答案

尝试运行此代码:

import System.Random (getStdGen, randomRIO)
import Data.List (permutations)

rndElem :: [a] -> IO Int
rndElem xs = do
  index <- randomRIO (0, length xs - 7)
  return index

然后将7更改为6到5,依此类推。

希望这能解释我关于'2'的问题,也许这会帮助你弄清楚代码在做什么。

另一答案

一个非常好的随机化有限列表算法是Fisher-Yates shuffle, aka Knuth shuffle。这是来自Rosetta Code的Haskell version

import System.Random
import Data.List
import Control.Monad

mkRands = mapM (randomRIO.(,)0 ). enumFromTo 1. pred

replaceAt :: Int -> a -> [a] -> [a]
replaceAt i c l = let (a,b) = splitAt i l in a++c:(drop 1 b)

swapElems :: (Int, Int) -> [a] -> [a]
swapElems (i,j) xs | i==j = xs
                   | otherwise = replaceAt j (xs!!i) $ replaceAt i (xs!!j) xs

knuthShuffle :: [a] -> IO [a]
knuthShuffle xs =
  liftM (foldr swapElems xs. zip [1..]) (mkRands (length xs))

以上是关于随机化一个Haskell列表的主要内容,如果未能解决你的问题,请参考以下文章

哈斯克尔。我很困惑这个代码片段是如何工作的

使用 gpipe 在 Haskell 中绘制彩色四边形

为啥这个 Haskell 代码可以成功地处理无限列表?

在Python中随机化一个列表[重复]

如何展平haskell中的列表列表

用 90 行 Haskell 代码实现 2048 游戏