Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Turning a generator based on System.Random into an FsCheck generator

Tags:

f#

fscheck

Suppose I am given a generator based on System.Random and I want to turn it into an FsCheck generator:

let myGen = MyGen(System.Random())
let fsGen = gen { return myGen.Generate() }

There are a couple of issues with this easy solution: the first is that the concept of size is ignored; I think it is not a big issue though, many generators ignore the size. The other issue impacts reproducibility because FsCheck generators are pure functions under the hood, the randomness is provided only by the sampling mechanism in the test runner. (this is clearly explained in this answer).

Now, a solution may be:

let fsGen = 
    gen {
        let! seed = Gen.choose(0, System.Int32.MaxValue)
        let myGen = MyGen(System.Random(seed))
        return myGen.Generate() }

but there is a performance penalty because I have to create a new instance of MyGen each time (with a potentially high initialization cost)

Any better way?

like image 443
Giacomo Citi Avatar asked Nov 18 '25 16:11

Giacomo Citi


1 Answers

Could the following work? Even though MyGen is random in nature, you can make it deterministic by fixing the seed:

let deterministicGen = MyGen(Random(42))

Due to the nature of Random, this isn't guaranteed to have a sufficiently random-like distribution, but if it does for your purposes, you can create a deterministic sequence of values generated by MyGen:

let deterministicValues = List.init 100 (fun _ -> deterministicGen.Generate())

This is only 100 values, but depending on your needs, you can create a bigger sample set of 1000, or perhaps even 10000 values.

Just like deterministicGen, deterministicValues is fixed: it's a list of values generated by MyGen.

You can easily ask FsCheck to randomly pick values from this list:

let fsGen = Gen.elements deterministicValues

Here, fsGen is an Gen<'a>, where 'a is whatever MyGen.Generate() returns.

like image 83
Mark Seemann Avatar answered Nov 21 '25 09:11

Mark Seemann