47 |
47 |
48 val ls = List(1,2,3,3,2,4,3,2,1) |
48 val ls = List(1,2,3,3,2,4,3,2,1) |
49 ls.distinct |
49 ls.distinct |
50 |
50 |
51 |
51 |
52 def distinctBy[B, C](xs: List[B], f: B => C, acc: List[C] = Nil): List[B] = xs match { |
52 def distinctBy[B, C](xs: List[B], |
|
53 f: B => C, |
|
54 acc: List[C] = Nil): List[B] = xs match { |
53 case Nil => Nil |
55 case Nil => Nil |
54 case (x::xs) => { |
56 case x::xs => { |
55 val res = f(x) |
57 val res = f(x) |
56 if (acc.contains(res)) distinctBy(xs, f, acc) |
58 if (acc.contains(res)) distinctBy(xs, f, acc) |
57 else x::distinctBy(xs, f, res::acc) |
59 else x::distinctBy(xs, f, res::acc) |
58 } |
60 } |
59 } |
61 } |
60 |
62 |
|
63 // distinctBy with the identity function is |
|
64 // just distinct |
61 distinctBy(ls, (x: Int) => x) |
65 distinctBy(ls, (x: Int) => x) |
62 |
66 |
63 |
67 |
64 val cs = List('A', 'b', 'a', 'c', 'B', 'D', 'd') |
68 val cs = List('A', 'b', 'a', 'c', 'B', 'D', 'd') |
65 |
69 |
68 |
72 |
69 |
73 |
70 // Type inference is local in Scala |
74 // Type inference is local in Scala |
71 |
75 |
72 def id[T](x: T) : T = x |
76 def id[T](x: T) : T = x |
73 |
|
74 |
77 |
75 val x = id(322) // Int |
78 val x = id(322) // Int |
76 val y = id("hey") // String |
79 val y = id("hey") // String |
77 val z = id(Set(1,2,3,4)) // Set[Int] |
80 val z = id(Set(1,2,3,4)) // Set[Int] |
78 |
81 |
83 // - variance (OO) |
86 // - variance (OO) |
84 // - bounds (subtyping) |
87 // - bounds (subtyping) |
85 // - quantification |
88 // - quantification |
86 |
89 |
87 // Java has issues with this too: Java allows |
90 // Java has issues with this too: Java allows |
88 // to write the following, but raises an exception |
91 // to write the following incorrect code, and |
89 // at runtime |
92 // only recovers by raising an exception |
90 |
93 // at runtime. |
91 //Object[] arr = new Integer[10]; |
94 |
92 //arr[0] = "Hello World"; |
95 // Object[] arr = new Integer[10]; |
|
96 // arr[0] = "Hello World"; |
93 |
97 |
94 |
98 |
95 // Scala gives you a compile-time error |
99 // Scala gives you a compile-time error |
96 |
100 |
97 var arr = Array[Int]() |
101 var arr = Array[Int]() |
110 abstract class Animal |
114 abstract class Animal |
111 case class Bird(name: String) extends Animal |
115 case class Bird(name: String) extends Animal |
112 case class Mammal(name: String) extends Animal |
116 case class Mammal(name: String) extends Animal |
113 case class Reptile(name: String) extends Animal |
117 case class Reptile(name: String) extends Animal |
114 |
118 |
115 println(new Bird("Sparrow")) |
119 println(Bird("Sparrow")) |
116 println(Bird("Sparrow").toString) |
120 println(Bird("Sparrow").toString) |
117 |
121 |
118 |
122 |
119 // you can override methods |
123 // you can override methods |
120 case class Bird(name: String) extends Animal { |
124 case class Bird(name: String) extends Animal { |
136 val half = Fraction(1, 2) |
140 val half = Fraction(1, 2) |
137 |
141 |
138 half.denom |
142 half.denom |
139 |
143 |
140 |
144 |
141 // in mandelbrot.scala I used complex (imaginary) numbers and implemented |
145 // In mandelbrot.scala I used complex (imaginary) numbers |
142 // the usual arithmetic operations for complex numbers |
146 // and implemented the usual arithmetic operations for complex |
|
147 // numbers. |
143 |
148 |
144 case class Complex(re: Double, im: Double) { |
149 case class Complex(re: Double, im: Double) { |
145 // represents the complex number re + im * i |
150 // represents the complex number re + im * i |
146 def +(that: Complex) = Complex(this.re + that.re, this.im + that.im) |
151 def +(that: Complex) = Complex(this.re + that.re, this.im + that.im) |
147 def -(that: Complex) = Complex(this.re - that.re, this.im - that.im) |
152 def -(that: Complex) = Complex(this.re - that.re, this.im - that.im) |
161 |
166 |
162 List(5, 2, 3, 4).sorted |
167 List(5, 2, 3, 4).sorted |
163 List(5, 2, 3, 4) sorted |
168 List(5, 2, 3, 4) sorted |
164 |
169 |
165 |
170 |
166 // to allow the notation n + m * i |
171 // ...to allow the notation n + m * i |
167 import scala.language.implicitConversions |
172 import scala.language.implicitConversions |
|
173 |
168 object i extends Complex(0, 1) |
174 object i extends Complex(0, 1) |
169 implicit def double2complex(re: Double) = Complex(re, 0) |
175 implicit def double2complex(re: Double) = Complex(re, 0) |
170 |
176 |
171 |
177 |
172 val inum1 = -2.0 + -1.5 * i |
178 val inum1 = -2.0 + -1.5 * i |
173 val inum2 = 1.0 + 1.5 * i |
179 val inum2 = 1.0 + 1.5 * i |
174 |
180 |
175 |
181 |
176 |
182 |
177 // all is public by default....so no public |
183 // All is public by default....so no public is needed. |
178 // you can have the usual restrictions about private values |
184 // You can have the usual restrictions about private |
179 // and methods, if you are MUTABLE(!!!) |
185 // values and methods, if you are MUTABLE !!! |
180 |
186 |
181 case class BankAccount(init: Int) { |
187 case class BankAccount(init: Int) { |
182 |
188 |
183 private var balance = init |
189 private var balance = init |
184 |
190 |
205 |
211 |
206 |
212 |
207 // A is the state type |
213 // A is the state type |
208 // C is the input (usually characters) |
214 // C is the input (usually characters) |
209 |
215 |
210 case class DFA[A, C](start: A, // starting state |
216 case class DFA[A, C](start: A, // starting state |
211 delta: (A, C) => A, // transition function |
217 delta: (A, C) => A, // transition function |
212 fins: A => Boolean) { // final states |
218 fins: A => Boolean) { // final states (Set) |
213 |
219 |
214 def deltas(q: A, s: List[C]) : A = s match { |
220 def deltas(q: A, s: List[C]) : A = s match { |
215 case Nil => q |
221 case Nil => q |
216 case c::cs => deltas(delta(q, c), cs) |
222 case c::cs => deltas(delta(q, c), cs) |
217 } |
223 } |
246 dfa.accepts("abaaa".toList) // true |
252 dfa.accepts("abaaa".toList) // true |
247 dfa.accepts("bbabaab".toList) // true |
253 dfa.accepts("bbabaab".toList) // true |
248 dfa.accepts("baba".toList) // false |
254 dfa.accepts("baba".toList) // false |
249 dfa.accepts("abc".toList) // false |
255 dfa.accepts("abc".toList) // false |
250 |
256 |
251 // another DFA test with a Sink state |
257 // another DFA with a Sink state |
252 abstract class S |
258 abstract class S |
253 case object S0 extends S |
259 case object S0 extends S |
254 case object S1 extends S |
260 case object S1 extends S |
255 case object S2 extends S |
261 case object S2 extends S |
256 case object Sink extends S |
262 case object Sink extends S |
257 |
263 |
258 // transition function with a sink state |
264 // transition function with a sink state |
259 val sigma : (S, Char) :=> S = |
265 val sigma : (S, Char) => S = |
260 { case (S0, 'a') => S1 |
266 { case (S0, 'a') => S1 |
261 case (S1, 'a') => S2 |
267 case (S1, 'a') => S2 |
262 case _ => Sink |
268 case _ => Sink |
263 } |
269 } |
264 |
270 |
266 |
272 |
267 dfa2.accepts("aa".toList) // true |
273 dfa2.accepts("aa".toList) // true |
268 dfa2.accepts("".toList) // false |
274 dfa2.accepts("".toList) // false |
269 dfa2.accepts("ab".toList) // false |
275 dfa2.accepts("ab".toList) // false |
270 |
276 |
|
277 // we could also have a dfa for numbers |
|
278 val sigmai : (S, Int) => S = |
|
279 { case (S0, 1) => S1 |
|
280 case (S1, 1) => S2 |
|
281 case _ => Sink |
|
282 } |
|
283 |
|
284 val dfa3 = DFA(S0, sigmai, Set[S](S2)) |
|
285 |
|
286 dfa3.accepts(List(1, 1)) // true |
|
287 dfa3.accepts(Nil) // false |
|
288 dfa3.accepts(List(1, 2)) // false |
|
289 |
271 |
290 |
272 |
291 |
273 |
292 |
274 // NFAs (Nondeterministic Finite Automata) |
293 // NFAs (Nondeterministic Finite Automata) |
275 |
294 |
276 |
295 |
277 case class NFA[A, C](starts: Set[A], // starting states |
296 case class NFA[A, C](starts: Set[A], // starting states |
278 delta: (A, C) => Set[A], // transition function |
297 delta: (A, C) => Set[A], // transition function |
279 fins: A => Boolean) { // final states |
298 fins: A => Boolean) { // final states |
280 |
299 |
281 // given a state and a character, what is the set of |
300 // given a state and a character, what is the set of |
282 // next states? if there is none => empty set |
301 // next states? if there is none => empty set |
283 def next(q: A, c: C) : Set[A] = |
302 def next(q: A, c: C) : Set[A] = |
284 Try(delta(q, c)) getOrElse Set[A]() |
303 Try(delta(q, c)) getOrElse Set[A]() |
285 |
|
286 def nexts(qs: Set[A], c: C) : Set[A] = |
|
287 qs.flatMap(next(_, c)) |
|
288 |
304 |
289 // depth-first version of accepts |
305 // depth-first version of accepts |
290 def search(q: A, s: List[C]) : Boolean = s match { |
306 def search(q: A, s: List[C]) : Boolean = s match { |
291 case Nil => fins(q) |
307 case Nil => fins(q) |
292 case c::cs => next(q, c).exists(search(_, cs)) |
308 case c::cs => next(q, c).exists(search(_, cs)) |
314 nfa.accepts("aaaaabbb".toList) // true |
330 nfa.accepts("aaaaabbb".toList) // true |
315 nfa.accepts("aaaaabbbaaa".toList) // false |
331 nfa.accepts("aaaaabbbaaa".toList) // false |
316 nfa.accepts("ac".toList) // false |
332 nfa.accepts("ac".toList) // false |
317 |
333 |
318 |
334 |
319 // Q: Why the kerfuffle about the polymorphic types in DFAs/NFAs |
335 // Q: Why the kerfuffle about the polymorphic types in DFAs/NFAs? |
320 // A: Subset construction |
336 // A: Subset construction |
321 |
337 |
322 def subset[A, C](nfa: NFA[A, C]) : DFA[Set[A], C] = { |
338 def subset[A, C](nfa: NFA[A, C]) : DFA[Set[A], C] = { |
323 DFA(nfa.starts, |
339 DFA(nfa.starts, |
324 { case (qs, c) => nfa.nexts(qs, c) }, |
340 { case (qs, c) => nfa.nexts(qs, c) }, |