在Haskell中随机化一个List

时间:2017-09-24 20:35:22

标签: haskell functional-programming

我正在尝试,给出一个列表,在Haskell中创建这些元素的随机排列。我已经在Javascript中尝试了这个算法并且它有效。我对Haskell很新,所以我可能没有看到任何东西。我很确定我收到单个元素而不是只包含一个元素的列表,这会让我的程序崩溃。我在以前的练习中遇到过这个问题,但仍然不知道如何解决。

算法将列表分开,直到获得一个元素。然后有50%的可能性,如果合并列表,另一个50%,以相反的方式合并。

这是代码:

-- A randomly chosen, program-scoped constant from the range [1 .. 10]
randomInt :: Int
randomInt = unsafePerformIO (getStdRandom (randomR (1, 10)))

-- Divides the list in half
divideList :: [a] -> ([a], [a])
divideList list = splitAt ((length list) `div` 2) list

-- Given a list, it creates a new one with the elements of said list
randomizeList :: Eq a => a -> [a]
randomizeList list = do
    let lists = (divideList list) in
        if (length list) > 1
        then if (randomInt > 5)
        then (randomizeList (fst lists) : randomizeList (snd lists))
        else (randomizeList (snd lists) : randomizeList (fst lists))
        else [list]

以下是Javascript代码,以防它有用:

function divideList(list){
    const length = list.length / 2;
    return {fst: list.splice(0, length), snd: list};
}
function randomizeList(list) {
    if(list.length == 1) return list;
    const lists = divideList(list);
    if(Math.random() > 0.5) return randomizeList(lists.fst).concat(randomizeList(lists.snd));
    else return randomizeList(lists.snd).concat(randomizeList(lists.fst));
}

提前致谢

2 个答案:

答案 0 :(得分:3)

随机化列表的快捷方式是:

module Main where                                                                                                                                                      

import Control.Monad (replicateM)                                                                                             
import Data.Function (on)
import Data.List     (sortBy)
import System.Random (randomRIO)                                                                                                                                                     

main :: IO ()
main = do                                                                                                                                                              
  putStrLn "not randomized"                                                                                                                                            
  let nums = [1..10]                                                                                                                                                   
  print nums                                                                                                                                                           
  putStrLn "randomized"                                                                                                                                                
  print =<< randomize nums                                                                                                                                             

randomize :: [a] -> IO [a]                                                                                                                                             
randomize xs = do                                                                                                                                                      
  ys <- replicateM (length xs) $ randomRIO (1 :: Int, 100000)                                                                                                          
  pure $ map fst $ sortBy (compare `on` snd) (zip xs ys)

此代码生成一个随机的数字列表,用原始列表将它们拉开,然后按生成的随机数对这些对进行排序。然后我们剥离随机数(map fst)并留下原始元素列表,但随机化。

通常,不建议使用unsafePerformIO

答案 1 :(得分:2)

您的代码存在一些问题,主要是琐碎的错误:

  1. 签名错误,应该是randomizeList :: Eq a => [a] -> [a] (从列表到列表,而不是从列表到列表)
  2. 虚假do在块的开头(只需删除)
  3. 列表与++连接,而不与:连接(后者在列表中添加元素)
  4. 在上一个else中,您需要返回list而不是[list](后者是列表清单)
  5. 以下内容应该有效:

    randomizeList :: Eq a => [a] -> [a]
    randomizeList list =
      let lists = (divideList list) in
        if (length list) > 1
        then if (randomInt > 5)
        then (randomizeList (fst lists) ++ randomizeList (snd lists))
        else (randomizeList (snd lists) ++ randomizeList (fst lists))
        else list