问题
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