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
|
// SPDX-License-Identifier: Apache-2.0
package firrtl.fuzzer
import scala.language.higherKinds
/** Wraps a function that takes a function an produces a random state transition and value
*
* @tparam State the type of the initial and resulting state of this random computation
* @tparam Gen the random context that wraps the return value of this function
* @tparam A the type of the value returned by this function
*/
final case class StateGen[State, Gen[_], A](run: State => Gen[(State, A)]) {
/** Creates a new [[StateGen]] that applies the function to the result of this [[StateGen]] and flattens the result
*/
def flatMap[B](fn: A => StateGen[State, Gen, B])(implicit GM: GenMonad[Gen]): StateGen[State, Gen, B] = {
StateGen { state =>
GM.flatMap(run(state)) { case (sx, a) =>
fn(a).run(sx)
}
}
}
/** Creates a new [[StateGen]] that applies the function to the result of this [[StateGen]]
*/
def map[B](f: A => B)(implicit GM: GenMonad[Gen]): StateGen[State, Gen, B] = StateGen { state =>
GM.map(run(state)) { case (sx, a) =>
sx -> f(a)
}
}
/** Returns the same [[StateGen]] but with a wider result type parameter
*/
def widen[B >: A](implicit GM: GenMonad[Gen]): StateGen[State, Gen, B] = StateGen { state =>
GM.map(run(state)) { case (state, a) => state -> a }
}
}
object StateGen {
/** Takes a constant value and turns it into a [[StateGen]]
*/
def pure[S, Gen[_]: GenMonad, A](a: A): StateGen[S, Gen, A] = {
StateGen((s: S) => GenMonad[Gen].const(s -> a))
}
/** Takes a random value generator and turns it into a [[StateGen]]
*/
def liftG[S, Gen[_]: GenMonad, A](ga: Gen[A]): StateGen[S, Gen, A] = {
StateGen((s: S) => GenMonad[Gen].map(ga)(s -> _))
}
/** Creates a [[StateGen]] produces a value from the input state without modifying it
*/
def inspect[S, Gen[_]: GenMonad, A](fn: S => A): StateGen[S, Gen, A] = {
StateGen(s => GenMonad[Gen].const((s, fn(s))))
}
/** Creates a [[StateGen]] produces a random value from the input state without modifying it
*/
def inspectG[S, Gen[_]: GenMonad, A](fn: S => Gen[A]): StateGen[S, Gen, A] = {
StateGen(s => GenMonad[Gen].map(fn(s)) { s -> _ })
}
}
|