Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to generate random array in Haskell?

Tags:

haskell

How can I generate random array using Data.Array?

I have function, that gives me a random number:

randomNumber :: (Random r) => r -> r -> IO r
randomNumber a b = getStdRandom (randomR (a,b))

And then I'm trying to use function from Data.Array to generate list

assocs $ array (1,100) [(i,i) | i <- (randomNumber 1 10)]

I know, that the type of randomNumber is IO, is there any method to convert IO Int -> Int? Or I need to use other methods to get random list? Should I do these functions with bind operator in do block?

like image 747
zerospiel Avatar asked Mar 15 '14 11:03

zerospiel


2 Answers

You should use functions to generate random list from a generator, that are pure, and then use getStdRandom:

randomList :: Int -> Int -> IO [Int]
randomList a b = getStdGen >>= return . randomRs (a,b)

The function that you need is randomRs. Then you set the generator to stdGen with getStdGen and you have your generator. The function randomList first gets the standard generator with getStdGen and then passes it to randomRs. Note that randomList can be rewritten without hiding the generator parameter:

randomList a b = getStdGen >>= \gen -> return (randomRs (a,b) gen)
like image 155
mariop Avatar answered Nov 03 '22 20:11

mariop


I'll continue as long as @mariop's answer tells about lists, not arrays, and try to explain a nature of Haskell randomness a little more.

(if you're not interested in theory, skip to the (tl;dr) section)

At first, let's choose a signature for our presumed function. I'll consider that you need a plain array (as in C or Java), indexed by consecutive natural numbers (if my guessing is wrong, please correct).

As you may know, all Haskell functions are pure and deterministic, so each function must always return same results for the same arguments. That's not the case of random, of course. The solution is to use pseudorandom values, where we have a generator. A generator itself is a complicated function that have an internal hidden state called seed, and can produce a value and a new generator with a new seed (which then can produce a new (value, generator) pair and so on). A good generator is built in way that the next value could not be predicted from the previous value (when the we don't know the seed), so they appear as random to the user.

In fact, all major random implementations in most languages are pseudorandom because the "true" random (which gets its values from the sources of "natural" randomness, called entropy, such as CPU temperature) is computatively expensive.

All so-called random functions in Haskell are dealing with the generator in some way. If you look at methods from the Random typeclass, they are divided in two groups:

  1. Those which get the random generator explicitly: randomR, random and so on. You can build an explicit generator, initialized with a seed, with mkStdRandom (or even make your own).

  2. Those which work in the IO monad: randomIO, randomRIO. They actually get the generator from the environment "carried" within the IO monad (with getStdRandom), and give it to function from the first group.

So, we can organize our function in either way:

--Arguments are generator, array size, min and max bound
generateArray :: (RangomGen g, Random r) => g -> Int -> r -> r -> Array Int r

or

--Arguments are array size, min and max bound
generateArray :: Random r => Int -> r -> r -> IO (Array Int r)

Because Haskell is lazy, there is no need to make a fixed set of random values — we can make an infinite one and take as many values as we need. The infinite list of random bounded values is produced by the randomRs function.

(tl;dr)

If the array is consecutive, the easier way is to build it from a plain values list rather than assocs (key, value) list:

generateArray gen size min max =
    listArray (0, size - 1) $ randomRs (min, max) gen

or

generateArray size min max =
    getStdGen >>= return . listArray (0, size - 1) . randomRs (min, max)
like image 5
Yuuri Avatar answered Nov 03 '22 20:11

Yuuri