Chris
Chris

Reputation: 179

How to create a randomly sized list of randomly generated numbers in Haskell

I'm new to haskell and I've been trying to figure out this problem for a while now. I want to generate a list of a random size using randomRIO and have that list be populated with random numbers using randomIO. I have tried to approach this problem by creating a function which takes in the randomly generated from randomRIO like so:

x <- randomRIO(1,5)
let y = randList x []

the function itself is something like this:

randList :: Int -> IO [Int] -> IO [Int]
randList 0 xs = return [xs]
randList g xs = do
            t <- randomIO
            let a = t:randList (g-1) xs 
            return [a]

I'm not sure how to handle the monad IO in a recursive function but this is how I'm thinking of it. Any help is appreciated thanks!

Upvotes: 0

Views: 191

Answers (1)

Frerich Raabe
Frerich Raabe

Reputation: 94299

You can use replicateM to repeatedly execute randomIO, generating a new number each time. You call randomRIO once up front to decide on the length of the list:

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

randList :: IO [Int]
randList = do
  len <- randomRIO (1,5)
  replicateM len randomIO

Now, your definition wasn't actually very far off. A couple of things though:

  • Given that you expect to be able to call randList x [], the second argument of randList clearly is a plain list. Not an IO action of some sort. So your type should be

    randList :: Int -> [Int] -> IO [Int]
    
  • In your first pattern match

    randList 0 xs = return [xs]
    

    Remember that xs is already a list. So when you do return [xs] you will get an IO [[Int]], a list of lists. What you want here is a plain return xs.

  • In your second definition

    randList g xs = do
        t <- randomIO
        let a = t:randList (g-1) xs 
        return [a]
    

    The expression t:randList ... makes no sense. The right-hand side of : must be a list. randList does not yield a list though, it yields an IO action. What you actually want to do is to treat the second argument of randList (the list) as an "accumulator", which is gradually built up. So you want to generate a number, add it to the accumulator, and then recurse with g decreased by one:

    randList g xs = do
        t <- randomIO
        randList (g-1) (t:xs)
    

Upvotes: 4

Related Questions