Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

List with random numbers in Haskell

I want to generate a list with random numbers in Haskell. I have to use the import System.Random library. I started doing something like that but it doesn't work. I have to create a list with N positions, and all these positions must have random numbers. Thanks!

System.Random library
import System.IO

x = randomRIO (1,6::Int) 

test :: IO Int
test = randomRIO (1,6::Int)
like image 773
Thiago Almeida Marques Avatar asked Nov 28 '22 14:11

Thiago Almeida Marques


2 Answers

You need to run randomRIO n times. For this you can use replicate. This will give you a list of monadic values, that you can transform into a monadic list of values with sequence:

test :: Int -> IO [Int]
test n = sequence $ replicate n $ randomRIO (1,6::Int)
like image 71
JP Moresmau Avatar answered Dec 16 '22 09:12

JP Moresmau


While JP Moresmau solution is certainly preferable, you might be interested in a more transparent solution that shines some light on the do notation and recursive functions using IO:

import System.Random (randomRIO)

randomList :: Int -> IO([Int])
randomList 0 = return []
randomList n = do
  r  <- randomRIO (1,6)
  rs <- randomList (n-1)
  return (r:rs) 

you should note the following:

  • if n == 0 the function will use return to wrap the empty list into IO and return this
  • else inside the do body it will first generate a random number r using randomRIO
  • next it will recursively generate a n-1 element list of random numbers using randomList (n-1) and bind it to rs
  • finally it uses return again to wrap r:rs (a n element list) into IO and return it

here is an example in GHCi:

λ> randomList 10
[2,4,4,5,2,2,2,5,6,2]

λ> randomList 10
[2,4,4,2,5,2,6,3,4,1]

seems random enough

remarks/exercise:

the function has a problem with certain values of n - can you spot it? And if so - can you change the function to be total?

having some fun

If you look closely you see that you can pull out randomRIO (1,6) :: IO Int there like this:

mList :: Int -> IO a -> IO([a])
mList 0 gen = return []
mList n gen = do
  r  <- gen
  rs <- mList(n-1) gen
  return (r:rs) 

which of course you would have to use like this:

λ> mList 10 $ randomRIO (1,6)
[2,2,2,5,5,1,3,6,6,1]

now this has been done before (in a slightly different/better) way and you can find it as replicateM in Control.Monad - with this import the function simplifies to:

import System.Random (randomRIO)
import Control.Monad (replicateM)

randomList :: Int -> IO([Int])
randomList n = replicateM n $ randomRIO (1,6)

fun fact internally this is implemented exactly as what JP answered ;)

like image 34
Random Dev Avatar answered Dec 16 '22 09:12

Random Dev