Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Force multiple evaluations of a function in F#

Tags:

f#

I am trying to develop a random number "generator" in F#.

I successfully created the following function:

let draw () =
    let rand = new Random()
    rand.Next(0,36)

This works fine and it generates a number between 0 and 36.

However, I am trying to create a function that runs this function several times.

I tried the following

let multipleDraws (n:int) =
    [for i in 1..n -> draw()]

However, I only get a single result, as draw is evaluated only once in the for comprehension.

How could I force multiple executions of the draw function?

like image 639
SRKX Avatar asked Sep 18 '11 21:09

SRKX


2 Answers

The problem is with the Random type. It uses the computer's time to generate a seed and then generate the random numbers. Since practically the time of the calls is identical, the same seed is generated and so are also same numbers returned.

This will solve your problem:

let draw =
    let rand = new Random()
    fun () ->
    rand.Next(0,36)

And then:

let multipleDraws (n:int) =
    [for i in 1..n -> draw()]
like image 184
Ramon Snir Avatar answered Nov 20 '22 16:11

Ramon Snir


Adding this to help explain Ramon's answer.

This code uses a lambda function.

let draw =
    let rand = new Random()
    fun () ->
    rand.Next(0,36)

It may be easier to understand what's happening if you give the lambda function a name.

let draw =
    let rand = new Random()
    let next() =
        rand.Next(0,36)
    next

The variable draw is being assigned the function next. You can move rand and next out of the scope of draw to see the assignment directly.

let rand = new Random()
let next() =
    rand.Next(0,36)
let draw = next

You can see from the above code that in Ramon's answer new Random is only called once while it is called many times in SRKX's example.

As mentioned by Ramon Random generates a sequence of numbers based on a random seed. It will always generate the same sequence of numbers if you use the same seed. You can pass random a seed like this new Random(2). If you do not pass it a value it uses the current time. So if you call new Random multiple times in a row without a seed it will most likely have the same seed (because the time hasn't changed). If the seed doesn't change then the first random number of the sequence will always be the same. If you try SRKX's original code and call multipleDraws with a large enough number, then the time will change during the loop and you will get back a sequence of numbers that changes every so often.

like image 24
gradbot Avatar answered Nov 20 '22 15:11

gradbot