-
Notifications
You must be signed in to change notification settings - Fork 30
/
Random.fs
99 lines (82 loc) · 3.2 KB
/
Random.fs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
namespace Hedgehog
open Hedgehog.Numeric
/// A generator for random values of type 'a
[<Struct>]
type Random<'a> =
| Random of (Seed -> Size -> 'a)
module Random =
let private unsafeRun (seed : Seed) (size : Size) (Random r : Random<'a>) : 'a =
r seed size
let run (seed : Seed) (size : Size) (r : Random<'a>) : 'a =
unsafeRun seed (max 1 size) r
let delay (f : unit -> Random<'a>) : Random<'a> =
Random <| fun seed size ->
f () |> unsafeRun seed size
let tryFinally (r : Random<'a>) (after : unit -> unit) : Random<'a> =
Random <| fun seed size ->
try
unsafeRun seed size r
finally
after ()
let tryWith (r : Random<'a>) (k : exn -> Random<'a>) : Random<'a> =
Random <| fun seed size ->
try
unsafeRun seed size r
with
x -> unsafeRun seed size (k x)
let constant (x : 'a) : Random<'a> =
Random <| fun _ _ ->
x
let map (f : 'a -> 'b) (r : Random<'a>) : Random<'b> =
Random <| fun seed size ->
r
|> unsafeRun seed size
|> f
let bind (r : Random<'a>) (k : 'a -> Random<'b>) : Random<'b> =
Random <| fun seed size ->
let seed1, seed2 = Seed.split seed
r
|> unsafeRun seed1 size
|> k
|> unsafeRun seed2 size
let replicate (times : int) (r : Random<'a>) : Random<List<'a>> =
Random <| fun seed0 size ->
let rec loop seed k acc =
if k <= 0 then
acc
else
let seed1, seed2 = Seed.split seed
let x = unsafeRun seed1 size r
loop seed2 (k - 1) (x :: acc)
loop seed0 times []
type Builder internal () =
member __.Return(x : 'a) : Random<'a> =
constant x
member __.ReturnFrom(m : Random<'a>) : Random<'a> =
m
member __.Bind(m : Random<'a>, k : 'a -> Random<'b>) : Random<'b> =
bind m k
/// Used to construct generators that depend on the size parameter.
let sized (f : Size -> Random<'a>) : Random<'a> =
Random <| fun seed size ->
unsafeRun seed size (f size)
/// Overrides the size parameter. Returns a generator which uses the
/// given size instead of the runtime-size parameter.
let resize (newSize : Size) (r : Random<'a>) : Random<'a> =
Random <| fun seed _ ->
run seed newSize r
/// Generates a random integral number in the given inclusive range.
let inline integral (range : Range<'a>) : Random<'a> =
Random <| fun seed size ->
let (lo, hi) = Range.bounds size range
let x, _ = Seed.nextBigInt (toBigInt lo) (toBigInt hi) seed
fromBigInt x
/// Generates a random floating point number in the given inclusive range.
let inline double (range : Range<double>) : Random<double> =
Random <| fun seed size ->
let (lo, hi) = Range.bounds size range
let x, _ = Seed.nextDouble lo hi seed
x
[<AutoOpen>]
module RandomBuilder =
let random = Random.Builder ()