-
Notifications
You must be signed in to change notification settings - Fork 3k
/
LocalEffects.scala
143 lines (122 loc) · 3.16 KB
/
LocalEffects.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
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
package fpinscala.localeffects
import fpinscala.monads._
object Mutable {
def quicksort(xs: List[Int]): List[Int] = if (xs.isEmpty) xs else {
val arr = xs.toArray
def swap(x: Int, y: Int) = {
val tmp = arr(x)
arr(x) = arr(y)
arr(y) = tmp
}
def partition(l: Int, r: Int, pivot: Int) = {
val pivotVal = arr(pivot)
swap(pivot, r)
var j = l
for (i <- l until r) if (arr(i) < pivotVal) {
swap(i, j)
j += 1
}
swap(j, r)
j
}
def qs(l: Int, r: Int): Unit = if (l < r) {
val pi = partition(l, r, l + (r - l) / 2)
qs(l, pi - 1)
qs(pi + 1, r)
}
qs(0, arr.length - 1)
arr.toList
}
}
sealed trait ST[S,A] { self =>
protected def run(s: S): (A,S)
def map[B](f: A => B): ST[S,B] = new ST[S,B] {
def run(s: S) = {
val (a, s1) = self.run(s)
(f(a), s1)
}
}
def flatMap[B](f: A => ST[S,B]): ST[S,B] = new ST[S,B] {
def run(s: S) = {
val (a, s1) = self.run(s)
f(a).run(s1)
}
}
}
object ST {
def apply[S,A](a: => A) = {
lazy val memo = a
new ST[S,A] {
def run(s: S) = (memo, s)
}
}
def runST[A](st: RunnableST[A]): A =
st[Null].run(null)._1
}
sealed trait STRef[S,A] {
protected var cell: A
def read: ST[S,A] = ST(cell)
def write(a: => A): ST[S,Unit] = new ST[S,Unit] {
def run(s: S) = {
cell = a
((), s)
}
}
}
object STRef {
def apply[S,A](a: A): ST[S, STRef[S,A]] = ST(new STRef[S,A] {
var cell = a
})
}
trait RunnableST[A] {
def apply[S]: ST[S,A]
}
// Scala requires an implicit Manifest for constructing arrays.
sealed abstract class STArray[S,A](implicit manifest: Manifest[A]) {
protected def value: Array[A]
def size: ST[S,Int] = ST(value.size)
// Write a value at the give index of the array
def write(i: Int, a: A): ST[S,Unit] = new ST[S,Unit] {
def run(s: S) = {
value(i) = a
((), s)
}
}
// Read the value at the given index of the array
def read(i: Int): ST[S,A] = ST(value(i))
// Turn the array into an immutable list
def freeze: ST[S,List[A]] = ST(value.toList)
def fill(xs: Map[Int,A]): ST[S,Unit] = ???
def swap(i: Int, j: Int): ST[S,Unit] = for {
x <- read(i)
y <- read(j)
_ <- write(i, y)
_ <- write(j, x)
} yield ()
}
object STArray {
// Construct an array of the given size filled with the value v
def apply[S,A:Manifest](sz: Int, v: A): ST[S, STArray[S,A]] =
ST(new STArray[S,A] {
lazy val value = Array.fill(sz)(v)
})
def fromList[S,A:Manifest](xs: List[A]): ST[S, STArray[S,A]] =
ST(new STArray[S,A] {
lazy val value = xs.toArray
})
}
object Immutable {
def noop[S] = ST[S,Unit](())
def partition[S](a: STArray[S,Int], l: Int, r: Int, pivot: Int): ST[S,Int] = ???
def qs[S](a: STArray[S,Int], l: Int, r: Int): ST[S, Unit] = ???
def quicksort(xs: List[Int]): List[Int] =
if (xs.isEmpty) xs else ST.runST(new RunnableST[List[Int]] {
def apply[S] = for {
arr <- STArray.fromList(xs)
size <- arr.size
_ <- qs(arr, 0, size - 1)
sorted <- arr.freeze
} yield sorted
})
}
import scala.collection.mutable.HashMap