Как извлечь int из FsCheck.Gen.choose

Я новичок в F# и не понимаю, как извлечь значение int из:

let autoInc = FsCheck.Gen.choose(1,999)

Компилятор говорит, что это тип Gen<int>, но не может получить из него int!. Мне нужно преобразовать его в десятичный, и оба типа несовместимы.


person mamcx    schedule 17.04.2015    source источник
comment
Вы ознакомились с функциональностью модуля Gen?   -  person ildjarn    schedule 17.04.2015
comment
да. Но я не понимаю этот код. В коде написано `позвольте выбрать (l, h) = rand |› map (range (l,h) ›› fst) `, но не могу расшифровать, что это значит   -  person mamcx    schedule 17.04.2015
comment
Результатом этого выражения является не число, а генератор чисел. Он не содержит внутри себя какого-либо конкретного числа, поэтому извлекать нечего. Если вы просто хотите сгенерировать случайное число, используйте System.Random.   -  person Fyodor Soikin    schedule 17.04.2015
comment
@mamcx: Ну, это исходный код для Gen.choose, но я не дал вам ссылку на исходный код по какой-то причине - я дал вам ссылку на документацию, которую вы должны прочитать.   -  person ildjarn    schedule 17.04.2015


Ответы (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.

person Nikos Baxevanis    schedule 17.04.2015

Привет, чтобы добавить к тому, что уже сказал вам Никос, вот как вы можете получить десятичную дробь от 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
person Random Dev    schedule 17.04.2015
comment
Или передать в Operators.decimal<^T>, например. .. |> Gen.sample 0 1 |> Seq.exactlyOne |> decimal - person Nikos Baxevanis; 17.04.2015
comment
да есть пара вариантов - выбирай что нравится - person Random Dev; 17.04.2015

Gen<'a> — это тип, который по существу абстрагирует функцию int -> 'a (фактический тип немного сложнее, но давайте пока его проигнорируем). Эта функция чистая, т. е. при задании одного и того же int вы каждый раз будете получать один и тот же экземпляр «a». Идея состоит в том, что FsCheck генерирует набор случайных целых чисел, передает их функции Gen, получает случайные экземпляры интересующего вас типа 'a и передает их тесту.

Таким образом, вы не можете получить the int. У вас есть функция, которая по заданному int генерирует другой int.

Gen.sample, как описано в другом ответе, по сути, просто передает последовательность случайных целых чисел в функцию и применяет ее к каждому, возвращая результаты.

Тот факт, что эта функция является чистой, важен, потому что это гарантирует воспроизводимость: если FsCheck находит значение, для которого тест не пройден, вы можете записать исходное целое число, которое было передано в функцию Gen — повторный запуск теста с этим начальным значением гарантированно сгенерирует одинаковые значения, т.е. воспроизвести ошибку.

person Kurt Schelfthout    schedule 17.04.2015