-
Notifications
You must be signed in to change notification settings - Fork 36
/
Generators.scala
103 lines (82 loc) · 2.65 KB
/
Generators.scala
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
100
101
102
103
package week1
/** This is the complete generators example, the simplified version for the
* exam is in the other file.
*/
object Generators {
trait Generator[+T] {
self => // an alias for "this"
def generate: T
def foreach[U](f: T => U) {
f(generate)
}
def map[S](f: T => S): Generator[S] = new Generator[S] {
def generate = f(self.generate) // also can be written "Generator.this.generate" or "this.generate"
}
def flatMap[S](f: T => Generator[S]): Generator[S] = new Generator[S] {
def generate = f(self.generate).generate
}
}
val integers = new Generator[Int] {
def generate = scala.util.Random.nextInt()
}
val booleans = integers.map(_ >= 0)
def choose(from: Int, to: Int) = new Generator[Int] {
def generate = if (from == to) from else scala.util.Random.nextInt(to - from) + from
}
def choose2(lo: Int, hi: Int): Generator[Int] =
for(x <- integers) yield lo + x % (hi - lo) //normalize in the interval between lo and hi using this modulator function
def oneOf[T](xs: T*): Generator[T] =
for(idx <- choose(0, xs.length)) yield xs(idx)
def single[T](x: T) = new Generator[T] {
def generate = x
}
def pairs[T, U](t: Generator[T], u: Generator[U]): Generator[(T, U)] = for {
x <- t
y <- u
} yield (x, y)
val pairDesugared: Generator[(Int, Int)] = integers flatMap {
x => integers map { y => (x, y) }
}
def test[T](r: Generator[T], noTimes: Int = 100)(test: T => Boolean) {
for (_ <- 0 until noTimes) {
val value = r.generate
assert(test(value), "Test failed for: "+value)
}
println("Test passed "+noTimes+" times")
}
def triangles(width: Int): Generator[(Int, Int)] = for {
x <- choose(0, width)
y <- choose(0, x)
} yield (x, y)
def emptyLists = single(Nil) // have them implement these
def nonEmptyLists = for {
head <- integers
tail <- lists
} yield head :: tail
def lists: Generator[List[Int]] = for {
cutoff <- booleans
list <- if (cutoff) emptyLists else nonEmptyLists
} yield list
trait Tree
case class Inner(left: Tree, right: Tree) extends Tree
case class Leaf(x: Int) extends Tree
def leafs: Generator[Leaf] = for {
x <- integers
} yield Leaf(x)
def inners: Generator[Inner] = for {
l <- trees
r <- trees
} yield Inner(l, r)
def trees: Generator[Tree] = for {
cutoff <- booleans
tree <- if (cutoff) leafs else inners
} yield tree
def main(args: Array[String]) {
println(triangles(20).generate)
println(lists.generate)
println(trees.generate)
test(pairs(lists, lists)) {
case (xs, ys) => (xs ::: ys).length > xs.length
}
}
}