Как извлечь int из FsCheck.Gen.choose
Я новичок в F# и не вижу, как извлечь значение int из:
let autoInc = FsCheck.Gen.choose(1,999)
Компилятор говорит, что тип Gen<int>
, но не могу получить int от этого! Мне нужно преобразовать его в десятичную, и оба типа не совместимы.
3 ответа
С точки зрения потребителя, вы можете использовать Gen.sample
комбинатор, который, учитывая генератор (например, Gen.choose
), возвращает вам несколько примеров значений.
Подпись Gen.sample
является:
val sample : size:int -> n:int -> gn:Gen<'a> -> 'a list
(* `size` is the size of generated test data
`n` is the number of samples to be returned
`gn` is the generator (e.g. `Gen.choose` in this case) *)
Вы можете игнорировать size
так как Gen.choose
игнорирует его, так как его распределение равномерно, и делает что-то вроде:
let result = Gen.choose(1,999) |> Gen.sample 0 1 |> Seq.exactlyOne |> decimal
(* 0 is the `size` (gets ignored by Gen.choose)
1 is the number of samples to be returned *)
result
должно быть значением в закрытом интервале [1, 999], например, 897.
Привет, чтобы добавить к тому, что Никос уже сказал вам, вот как вы можете получить десятичное число от 1 до 999:
#r "FsCheck.dll"
open FsCheck
let decimalBetween1and999 : Gen<decimal> =
Arb.generate |> Gen.suchThat (fun d -> d >= 1.0m && d <= 999.0m)
let sample () =
decimalBetween1and999
|> Gen.sample 0 1
|> List.head
теперь вы можете просто использовать sample ()
чтобы получить случайный десятичный обратно.
В случае, если вы просто хотите целые числа от 1 до 999, но конвертируйте их в decimal
Вы можете просто сделать:
let decimalIntBetween1and999 : Gen<decimal> =
Gen.choose (1,999)
|> Gen.map decimal
let sampleInt () =
decimalIntBetween1and999
|> Gen.sample 0 1
|> List.head
что вы, вероятно, действительно хотите сделать вместо
Используйте это, чтобы написать вам несколько хороших типов и проверить свойства вроде этого (здесь мы используем Xunit в качестве тестовой среды и пакет FsCheck.Xunit:
open FsCheck
open FsCheck.Xunit
type DecTo999 = DecTo999 of decimal
type Generators =
static member DecTo999 =
{ new Arbitrary<DecTo999>() with
override __.Generator =
Arb.generate
|> Gen.suchThat (fun d -> d >= 1.0m && d <= 999.0m)
|> Gen.map DecTo999
}
[<Arbitrary(typeof<Generators>)>]
module Tests =
type Marker = class end
[<Property>]
let ``example property`` (DecTo999 d) =
d > 1.0m
Gen<'a>
это тип, который по существу абстрагирует функцию int -> 'a
(фактический тип немного сложнее, но давайте пока проигнорируем). Эта функция является чистой, то есть, когда ей присваивается один и тот же int, вы каждый раз получаете один и тот же экземпляр back. Идея состоит в том, что FsCheck генерирует кучу случайных целых чисел, передает их Gen
функция, случайные экземпляры типа 'a
вы заинтересованы, и кормите их для теста.
Таким образом, вы не можете выйти из инт. У вас в руках есть функция, которая дает int, генерирует другой int.
Gen.sample
как описано в другом ответе, по существу, просто передает последовательность случайных целочисленных значений в функцию и применяет ее к каждому, возвращая результаты.
Тот факт, что эта функция является чистой, важен, потому что она гарантирует воспроизводимость: если FsCheck находит значение, для которого тест не пройден, вы можете записать исходный int, который был передан Gen
функция - повторный запуск теста с этим начальным значением гарантирует получение тех же значений, т. е. воспроизводит ошибку.