Skip to content

Commit 1bae57f

Browse files
Add random::shuffle and random::pick (#1361)
Add the two functions `shuffle` and `pick` to the `random` module in the stdlib according the issue #1307 --------- Co-authored-by: Philipp Schuster <philipp.schuster@uni-tuebingen.de>
1 parent f992caa commit 1bae57f

5 files changed

Lines changed: 101 additions & 6 deletions

File tree

examples/stdlib/random/pick.check

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
5
2+
5
3+
6
4+
5
5+
3
6+
0
7+
5
8+
9
9+
2
10+
1
11+
0

examples/stdlib/random/pick.effekt

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
import random
2+
import array
3+
4+
def main() = {
5+
val arr = array::build(10) { i => i }
6+
val singleton = array::build(1) { i => i }
7+
val empty = array(0, 0)
8+
9+
with minstd(1337)
10+
10.repeat{ println(pick(arr)) }
11+
println(pick(singleton))
12+
}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
Array(5, 7, 4, 9, 1, 0, 2, 8, 6, 3)
2+
3+
Array(5, 7, 4, 9, 1, 0, 2, 8, 6, 3)
4+
5+
Array(8, -5, -3, 7, -4, -8, -7, -2, -6, 2, 3, 6, -10, 0, 4, -9, -1, 5, 1, 9)
6+
7+
Array(D, B, C, A)
8+
Array(B, D, C, A)
9+
Array(D, C, B, A)
10+
Array(C, D, B, A)
11+
Array(D, A, B, C)
12+
Array(C, B, A, D)
13+
Array(B, D, C, A)
14+
Array(C, B, D, A)
15+
Array(D, A, C, B)
16+
Array(B, D, C, A)
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
import random
2+
import array
3+
import list
4+
5+
def main() = {
6+
val left = array::build(10) { i => i }
7+
val right = array::build(10) { i => i }
8+
9+
with minstd(1337)
10+
shuffle(left)
11+
println(left)
12+
13+
println("")
14+
15+
with minstd(1337)
16+
shuffle(right)
17+
println(right)
18+
19+
println("")
20+
21+
val shuffled = array::build(20) { i => i - 10 }
22+
with minstd(42);
23+
shuffle(shuffled)
24+
println(shuffled)
25+
26+
println("")
27+
28+
with minstd(1337)
29+
val abcd = array::fromList(["A", "B", "C", "D"])
30+
10.repeat {
31+
shuffle(abcd)
32+
println(abcd)
33+
}
34+
}

libraries/common/random.effekt

Lines changed: 28 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
module random
22

33
import stream
4+
import array
5+
import option
6+
import exception
47
import io/filesystem
58
import io/error
69

@@ -38,7 +41,7 @@ def minstd(seed: Int): Unit / emit[Byte] = {
3841
if (result < 0) result + m else result
3942
}
4043

41-
while (true) {
44+
forever {
4245
state = nextInt()
4346
val b = state.mod(256).toByte
4447
do emit(b)
@@ -88,14 +91,14 @@ def devurandom { randomnessReader: () => Unit / random }: Unit / Exception[IOErr
8891

8992
def randomByte(): Byte / random = do random()
9093
def randomBytes(): Unit / {emit[Byte], random} =
91-
while (true) do emit(do random())
94+
forever { do emit(do random()) }
9295

9396
def randomBool(): Bool / random = {
9497
val b = do random()
9598
b.toInt.mod(2) == 1
9699
}
97100
def randomBools(): Unit / {emit[Bool], random} =
98-
while (true) do emit(randomBool())
101+
forever { do emit(randomBool()) }
99102

100103
def randomInt32(): Int / random = {
101104
var result = 0
@@ -107,7 +110,7 @@ def randomInt32(): Int / random = {
107110
result.mod(1.bitwiseShl(31)).abs * if (signBit) 1 else -1
108111
}
109112
def randomInt32s(): Unit / {emit[Int], random} =
110-
while (true) do emit(randomInt32())
113+
forever { do emit(randomInt32()) }
111114

112115
/// `max` is _inclusive_!
113116
def randomInt(min: Int, max: Int): Int / random = {
@@ -126,17 +129,36 @@ def randomInt(min: Int, max: Int): Int / random = {
126129
min + (abs(result).mod(range))
127130
}
128131
}
132+
129133
/// `max` is _inclusive_!
130134
def randomInts(min: Int, max: Int): Unit / {emit[Int], random} =
131-
while (true) do emit(randomInt(min, max))
135+
forever { do emit(randomInt(min, max)) }
132136

133137

134138
/// Random double between 0.0 and 1.0
135139
def randomDouble(): Double / random =
136140
(randomInt32().toDouble / 1.bitwiseShl(31).toDouble).abs
137141
// This is not perfect, but it will do for now.
138142
def randomDoubles(): Unit / {emit[Double], random} =
139-
while (true) do emit(randomDouble())
143+
forever { do emit(randomDouble()) }
144+
145+
/// Shuffle an array in-place using the Fisher-Yates algorithm.
146+
def shuffle[A](arr: Array[A]): Unit / random = {
147+
val n = arr.size
148+
each(0, n - 1) { i =>
149+
arr.swap(i, randomInt(i, n - 1))
150+
}
151+
}
152+
153+
/// Pick a random element from an array.
154+
///
155+
/// Panics when called on an empty array.
156+
def pick[A](arr: Array[A]): A / random =
157+
if (arr.size == 0) {
158+
panic("Pick from an empty array")
159+
} else {
160+
arr.get(randomInt(0, arr.size - 1))
161+
}
140162

141163

142164
namespace examples {

0 commit comments

Comments
 (0)