Превращение генератора на основе System.Random в генератор FsCheck

Предположим, мне дали генератор на основе System.Random и я хочу превратить его в генератор FsCheck:

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

Есть несколько проблем с этим простым решением: во-первых, концепция размера игнорируется; Я думаю, что это не большая проблема, хотя многие генераторы игнорируют размер. Другая проблема влияет на воспроизводимость, потому что генераторы FsCheck являются чистыми функциями под капотом, случайность обеспечивается только механизмом выборки в тестовом средстве. (это четко объясняется в этом ответе).

Теперь решение может быть:

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

но есть снижение производительности, потому что я должен создать новый экземпляр MyGen каждый раз (с потенциально высокой стоимостью инициализации)

Есть ли лучший способ?

1 ответ

Решение

Может ли следующая работа? Даже если MyGen случайный характер, вы можете сделать его детерминированным, зафиксировав начальное число:

let deterministicGen = MyGen(Random(42))

Из-за характера Randomэто не гарантирует достаточно случайное распределение, но если это имеет место для ваших целей, вы можете создать детерминированную последовательность значений, генерируемых MyGen:

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

Это только 100 значений, но в зависимости от ваших потребностей, вы можете создать больший выборочный набор из 1000 или, возможно, даже 10000 значений.

Как deterministicGen, deterministicValues исправлено: это список значений, сгенерированных MyGen,

Вы можете легко попросить FsCheck случайным образом выбрать значения из этого списка:

let fsGen = Gen.elements deterministicValues

Вот, fsGen является Gen<'a>, где 'a что угодно MyGen.Generate() возвращается.

Другие вопросы по тегам