How extract the int from a FsCheck.Gen.choose

耗尽温柔 提交于 2019-12-12 21:08:06

问题


I'm new on F#, and can't see how extract the int value from:

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

The compiler say the type is Gen<int>, but can't get the int from it!. I need to convert it to decimal, and both types are not compatible.


回答1:


From a consumer's point of view, you can use the Gen.sample combinator which, given a generator (e.g. Gen.choose), gives you back some example values.

The signature of Gen.sample is:

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) *)

You can ignore size because Gen.choose ignores it, as its distribution is uniform, and do something like:

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 *)

The result should be a value in the closed interval [1, 999], e.g. 897.




回答2:


Hi to add to what Nikos already told you, this is how you can get an decimal between 1 and 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 

you can now just use sample () to get a random decimal back.

In case you just want integers between 1 and 999 but have those converted to decimal you can just do:

let decimalIntBetween1and999 : Gen<decimal> =
    Gen.choose (1,999)
    |> Gen.map decimal

let sampleInt () = 
    decimalIntBetween1and999
    |> Gen.sample 0 1 
    |> List.head 

what you probably really want to do instead

Is use this to write you some nice types and check properties like this (here using Xunit as a test-framework and the FsCheck.Xunit package:

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



回答3:


Gen<'a> is a type that essentially abstracts a function int -> 'a (the actual type is a bit more complex, but let's ignore for now). This function is pure, i.e. when given the same int, you'll get the same instance of 'a back every time. The idea is that FsCheck generates a bunch of random ints, feeds them to the Gen function, out come random instances of the type 'a you're interested in, and feeds those to a test.

So you can't really get out the int. You have in your hands a function that given an int, generates another int.

Gen.sample as described in another answer essentially just feeds a sequence of random ints to the function and applies it to each, returning the results.

The fact that this function is pure is important because it guarantees reproducibility: if FsCheck finds a value for which a test fails, you can record the original int that was fed into the Gen function - rerunning the test with that seed is guaranteed to generate the same values, i.e. reproduce the bug.



来源:https://stackoverflow.com/questions/29689437/how-extract-the-int-from-a-fscheck-gen-choose

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!