1 // Scala Lecture 2 |
1 // Scala Lecture 2 |
2 //================= |
2 //================= |
3 |
3 |
4 |
4 |
5 // Implicits |
|
6 //=========== |
|
7 // |
|
8 // for example adding your own methods to Strings: |
|
9 // imagine you want to increment strings, like |
|
10 // |
|
11 // "HAL".increment |
|
12 // |
|
13 // you can avoid ugly fudges, like a MyString, by |
|
14 // using implicit conversions |
|
15 |
|
16 |
|
17 implicit class MyString(s: String) { |
|
18 def increment = for (c <- s) yield (c + 1).toChar |
|
19 } |
|
20 |
|
21 "HAL".increment |
|
22 |
|
23 |
|
24 |
|
25 // Option type |
5 // Option type |
26 //============= |
6 //============= |
27 |
7 |
28 //in Java if something unusually happens, you return null |
8 //in Java if something unusually happens, you return null; |
29 //in Scala you use Option |
9 //in Scala you use Option |
30 // - if the value is present, you use Some(value) |
10 // - if the value is present, you use Some(value) |
31 // - if no value is present, you use None |
11 // - if no value is present, you use None |
32 |
12 |
33 |
13 |
47 |
27 |
48 for ((x, y) <- ps) yield { |
28 for ((x, y) <- ps) yield { |
49 if (y == 0) None else Some(x / y) |
29 if (y == 0) None else Some(x / y) |
50 } |
30 } |
51 |
31 |
52 // getOrElse is to set a default value |
32 // getOrElse is for setting a default value |
53 |
33 |
54 val lst = List(None, Some(1), Some(2), None, Some(3)) |
34 val lst = List(None, Some(1), Some(2), None, Some(3)) |
55 for (x <- lst) yield x getOrElse 0 |
35 for (x <- lst) yield x.getOrElse(0) |
56 |
36 |
57 |
37 |
|
38 |
|
39 |
|
40 // error handling with option (no exceptions) |
|
41 // |
|
42 // Try(something).getOrElse(what_to_do_in_an_exception) |
|
43 // |
58 import scala.util._ |
44 import scala.util._ |
59 import io.Source |
45 import io.Source |
60 // error handling with option |
46 |
61 // |
47 Source.fromURL("""http://www.inf.kcl.ac.uk/staff/urbanc/""").mkString |
62 // Try(something).getOrElse(what_to_do_in_an_exception) |
|
63 |
|
64 Source.fromURL("""http://www.inf.kcl.ac.uk/staff/urbanccc/""").mkString |
|
65 |
48 |
66 Try(Source.fromURL("""http://www.inf.kcl.ac.uk/staff/urbanc/""").mkString).getOrElse("") |
49 Try(Source.fromURL("""http://www.inf.kcl.ac.uk/staff/urbanc/""").mkString).getOrElse("") |
67 |
50 |
68 Try(Some(Source.fromURL("""http://www.inf.kcl.ac.uk/staff/urbanc/""").mkString)).getOrElse(None) |
51 Try(Some(Source.fromURL("""http://www.inf.kcl.ac.uk/staff/urbanc/""").mkString)).getOrElse(None) |
69 |
52 |
70 |
53 // a function that turns strings into numbers |
71 Integer.parseInt("12u34") |
54 Integer.parseInt("12u34") |
72 |
55 |
73 def get_me_an_int(s: String): Option[Int] = |
56 def get_me_an_int(s: String): Option[Int] = |
74 Try(Some(Integer.parseInt(s))).getOrElse(None) |
57 Try(Some(Integer.parseInt(s))).getOrElse(None) |
75 |
58 |
84 // see the value, you have to put yourself in the shoes of the |
67 // see the value, you have to put yourself in the shoes of the |
85 // consumer of the get_me_an_int function, and imagine you didn't |
68 // consumer of the get_me_an_int function, and imagine you didn't |
86 // write that function. |
69 // write that function. |
87 // |
70 // |
88 // In Java, if you didn't write this function, you'd have to depend on |
71 // In Java, if you didn't write this function, you'd have to depend on |
89 // the Javadoc of the get_me_an_int. If you didn't look at the Javadoc |
72 // the Javadoc of the get_me_an_int. If you didn't look at the Javadoc, |
90 // for the Java, you might not know that get_me_an_int could return a |
73 // you might not know that get_me_an_int could return a null, and your |
91 // null, and your code could potentially throw a NullPointerException. |
74 // code could potentially throw a NullPointerException. |
92 |
|
93 |
75 |
94 |
76 |
95 |
77 |
96 // Type abbreviations |
78 // Type abbreviations |
97 //==================== |
79 //==================== |
99 // some syntactic convenience |
81 // some syntactic convenience |
100 type Pos = (int, Int) |
82 type Pos = (int, Int) |
101 |
83 |
102 type Board = List[List[Int]] |
84 type Board = List[List[Int]] |
103 |
85 |
|
86 |
|
87 |
|
88 // Implicits |
|
89 //=========== |
|
90 // |
|
91 // for example adding your own methods to Strings: |
|
92 // imagine you want to increment strings, like |
|
93 // |
|
94 // "HAL".increment |
|
95 // |
|
96 // you can avoid ugly fudges, like a MyString, by |
|
97 // using implicit conversions |
|
98 |
|
99 |
|
100 implicit class MyString(s: String) { |
|
101 def increment = for (c <- s) yield (c + 1).toChar |
|
102 } |
|
103 |
|
104 "HAL".increment |
104 |
105 |
105 |
106 |
106 // No return in Scala |
107 // No return in Scala |
107 //==================== |
108 //==================== |
108 |
109 |
168 case 1 => "one" |
177 case 1 => "one" |
169 case 2 => "two" |
178 case 2 => "two" |
170 case _ => "many" |
179 case _ => "many" |
171 } |
180 } |
172 |
181 |
|
182 get_me_a_string(0) |
|
183 |
173 // User-defined Datatypes |
184 // User-defined Datatypes |
174 //======================== |
185 //======================== |
175 |
186 |
176 abstract class Tree |
187 abstract class Tree |
177 case class Node(elem: Int, left: Tree, right: Tree) extends Tree |
188 case class Node(elem: Int, left: Tree, right: Tree) extends Tree |
178 case class Leaf() extends Tree |
189 case class Leaf() extends Tree |
|
190 |
179 |
191 |
180 def insert(tr: Tree, n: Int): Tree = tr match { |
192 def insert(tr: Tree, n: Int): Tree = tr match { |
181 case Leaf() => Node(n, Leaf(), Leaf()) |
193 case Leaf() => Node(n, Leaf(), Leaf()) |
182 case Node(m, left, right) => |
194 case Node(m, left, right) => |
183 if (n == m) Node(m, left, right) |
195 if (n == m) Node(m, left, right) |
221 case (Clown(), Peasant(_)) => true |
233 case (Clown(), Peasant(_)) => true |
222 case _ => false |
234 case _ => false |
223 } |
235 } |
224 |
236 |
225 val people = List(Knight("David"), |
237 val people = List(Knight("David"), |
226 Peer("Duke", "Norfolk", 42), |
238 Peer("Duke", "Norfolk", 84), |
227 Peasant("Christian"), |
239 Peasant("Christian"), |
228 King(), |
240 King(), |
229 Clown()) |
241 Clown()) |
230 |
242 |
231 println(people.sortWith(superior(_, _))) |
243 println(people.sortWith(superior(_, _)).mkString(", ")) |
|
244 |
|
245 |
232 |
246 |
233 // Higher-Order Functions |
247 // Higher-Order Functions |
234 //======================== |
248 //======================== |
235 |
249 |
236 // functions can take functions as arguments |
250 // functions can take functions as arguments |
256 |
270 |
257 // in my collatz.scala |
271 // in my collatz.scala |
258 //(1 to bnd).map(i => (collatz(i), i)).maxBy(_._1) |
272 //(1 to bnd).map(i => (collatz(i), i)).maxBy(_._1) |
259 |
273 |
260 |
274 |
261 // type of functions |
275 // type of functions, for example f: Int => Int |
|
276 |
262 def my_map_int(lst: List[Int], f: Int => Int): List[Int] = lst match { |
277 def my_map_int(lst: List[Int], f: Int => Int): List[Int] = lst match { |
263 case Nil => Nil |
278 case Nil => Nil |
264 case x::xs => f(x)::my_map_int(xs, f) |
279 case x::xs => f(x)::my_map_int(xs, f) |
265 } |
280 } |
266 |
281 |
267 my_map_int(lst, square) |
282 my_map_int(lst, square) |
268 |
283 |
|
284 // other function types |
|
285 // |
|
286 // f1: (Int, Int) => Int |
|
287 // f2: List[String] => Option[Int] |
|
288 // ... |
|
289 |
269 |
290 |
270 def sumOf(f: Int => Int, lst: List[Int]): Int = lst match { |
291 def sumOf(f: Int => Int, lst: List[Int]): Int = lst match { |
271 case Nil => 0 |
292 case Nil => 0 |
272 case x::xs => f(x) + sumOf(f, xs) |
293 case x::xs => f(x) + sumOf(f, xs) |
273 } |
294 } |
318 |5....9.6. |
350 |5....9.6. |
319 |..6.2..3. |
351 |..6.2..3. |
320 |1..5...92 |
352 |1..5...92 |
321 |..7.9.41.""".stripMargin.replaceAll("\\n", "") |
353 |..7.9.41.""".stripMargin.replaceAll("\\n", "") |
322 |
354 |
323 |
|
324 type Pos = (Int, Int) |
355 type Pos = (Int, Int) |
325 val EmptyValue = '.' |
356 val EmptyValue = '.' |
326 val MaxValue = 9 |
357 val MaxValue = 9 |
327 |
358 |
328 val allValues = "123456789".toList |
359 val allValues = "123456789".toList |
329 val indexes = (0 to 8).toList |
360 val indexes = (0 to 8).toList |
330 |
361 |
|
362 |
|
363 |
|
364 |
331 def empty(game: String) = game.indexOf(EmptyValue) |
365 def empty(game: String) = game.indexOf(EmptyValue) |
|
366 def isDone(game: String) = empty(game) == -1 |
332 def emptyPosition(game: String) = (empty(game) % MaxValue, empty(game) / MaxValue) |
367 def emptyPosition(game: String) = (empty(game) % MaxValue, empty(game) / MaxValue) |
333 def isDone(game: String) = empty(game) == -1 |
368 |
334 |
369 |
335 def row(game: String, y: Int): List[Char] = indexes.map(col => game(y * MaxValue + col)) |
370 def get_row(game: String, y: Int) = indexes.map(col => game(y * MaxValue + col)) |
336 def col(game: String, x: Int): List[Char] = indexes.map(row => game(x + row * MaxValue)) |
371 def get_col(game: String, x: Int) = indexes.map(row => game(x + row * MaxValue)) |
337 |
372 |
338 def box(game: String, pos: Pos): List[Char] = { |
373 def get_box(game: String, pos: Pos): List[Char] = { |
339 def base(p: Int): Int = (p / 3) * 3 |
374 def base(p: Int): Int = (p / 3) * 3 |
340 val x0 = base(pos._1) |
375 val x0 = base(pos._1) |
341 val y0 = base(pos._2) |
376 val y0 = base(pos._2) |
342 val ys = (y0 until y0 + 3).toList |
377 val ys = (y0 until y0 + 3).toList |
343 (x0 until x0 + 3).toList.flatMap(x => ys.map(y => game(x + y * MaxValue))) |
378 (x0 until x0 + 3).toList.flatMap(x => ys.map(y => game(x + y * MaxValue))) |
344 } |
379 } |
345 |
380 |
346 |
381 |
347 //row(game0, 0) |
382 //get_row(game0, 0) |
348 //row(game0, 1) |
383 //get_row(game0, 1) |
349 //box(game0, (3,1)) |
384 //get_box(game0, (3,1)) |
350 |
385 |
351 def update(game: String, pos: Int, value: Char): String = game.updated(pos, value) |
386 def update(game: String, pos: Int, value: Char): String = game.updated(pos, value) |
352 |
387 |
353 def toAvoid(game: String, pos: Pos): List[Char] = |
388 def toAvoid(game: String, pos: Pos): List[Char] = |
354 (col(game, pos._1) ++ row(game, pos._2) ++ box(game, pos)).distinct |
389 (get_col(game, pos._1) ++ get_row(game, pos._2) ++ get_box(game, pos)) |
355 |
390 |
356 def candidates(game: String, pos: Pos): List[Char] = allValues diff toAvoid(game,pos) |
391 def candidates(game: String, pos: Pos): List[Char] = allValues diff toAvoid(game,pos) |
357 |
392 |
358 //candidates(game0, (0,0)) |
393 //candidates(game0, (0,0)) |
359 |
394 |
360 def pretty(game: String): String = "\n" + (game sliding (MaxValue, MaxValue) mkString "\n") |
395 def pretty(game: String): String = "\n" + (game sliding (MaxValue, MaxValue) mkString "\n") |
361 |
396 |
362 def search(game: String): List[String] = { |
397 def search(game: String): List[String] = { |
363 if (isDone(game)) List(game) |
398 if (isDone(game)) List(game) |
364 else |
399 else |
365 candidates(game, emptyPosition(game)).par.map(c => search(update(game, empty(game), c))).toList.flatten |
400 candidates(game, emptyPosition(game)).map(c => search(update(game, empty(game), c))).toList.flatten |
366 } |
401 } |
367 |
402 |
368 |
403 |
369 val game1 = """23.915... |
404 val game1 = """23.915... |
370 |...2..54. |
405 |...2..54. |