I wrote this trying to set up a Haskell testcase. The aim is to take a list and add a single duplicate from any place in the list to anywhere else in the list. I'm trying to learn to use the Random Monad properly so the main aims should be clear, simple, idiomatic and pure code. However any recommendations for improvement are appreciated.
The code here has most of the improvements suggested by @Petr in the review of the previous version, however
- I'm still using lists rather than sequences because the code I plan to test uses lists
- I still have an infinite list function because I want to be able to use it easily from IO code where the number of strings to be generated isn't known in advance. I believe that since the Random Monad uses incremental state based on the State Monad, it should be okay to generate infinite lists with it.
-- DataListDuplicator.hs by Michael De La Rue 2014 -- licensed to StackExchange codereview under cc by-sa 3.0 -- may be used under AGPLv3 module DataListDuplicator where import Control.Monad.Random infiniteDuplicateLists :: (MonadRandom m) => [a] -> m [[a]] infiniteDuplicateLists = mapM addRandomDuplicate . repeat addRandomDuplicate :: MonadRandom m => [a] -> m [a] addRandomDuplicate genlist = do frompos <- getRandomR (0 ,llen - 1) topos <- getRandomR (0 ,llen) let newlist = listEntryDuplicate frompos topos genlist return newlist where llen = length genlist listEntryDuplicate from to list = start ++ [repeat] ++ end where repeat = list !! from (start, end) = splitAt to list
Here's a little program which drives that:
-- duplicate-to-list-randmonad.hs by Michael De La Rue 2014 -- licensed to StackExchange codereview under cc by-sa 3.0 -- may also be used under AGPLv3 -- N.B. Trivial copying of code fragments does not normally require any license. import Data.List import Control.Monad.Random import DataListDuplicator main :: IO () main = do putStrLn $ "list comparison " ++ prettyList list g <- getStdGen let shuffled = evalRand (infiniteDuplicateLists list) g putStrLn $ "lists after \n" ++ intercalate "\n" ( map prettyList (take 5 shuffled)) where list = ["a","b","c"] prettyList :: (Show a) => [a] -> String prettyList list = " [ " ++ intercalate "," (map show list) ++ " ] "