37 for (i <- (0 until lst.length).toList) yield square(lst(i)) |
37 for (i <- (0 until lst.length).toList) yield square(lst(i)) |
38 |
38 |
39 // this is just so prone to off-by-one errors; |
39 // this is just so prone to off-by-one errors; |
40 // write instead |
40 // write instead |
41 |
41 |
42 for (e <- lst) yield square(e) |
42 for (e <- lst; if (e % 2) == 0; if (e != 4)) yield square(e) |
43 |
43 |
44 |
44 |
45 //this works for sets as well |
45 //this works for sets as well |
46 val st = Set(1, 2, 3, 4, 5, 6, 7, 8, 9) |
46 val st = Set(1, 2, 3, 4, 5, 6, 7, 8, 9) |
47 |
47 |
69 |
69 |
70 |
70 |
71 |
71 |
72 // know when to use yield and when not: |
72 // know when to use yield and when not: |
73 |
73 |
74 for (e <- Set(1, 2, 3, 4, 5, 6, 7, 8, 9); if e < 5) yield square(e) |
74 val test = |
|
75 for (e <- Set(1, 2, 3, 4, 5, 6, 7, 8, 9); if e < 5) yield square(e) |
|
76 |
75 |
77 |
76 |
78 |
77 // Option type |
79 // Option type |
78 //============= |
80 //============= |
79 |
81 |
81 //in Scala you use Option |
83 //in Scala you use Option |
82 // - if the value is present, you use Some(value) |
84 // - if the value is present, you use Some(value) |
83 // - if no value is present, you use None |
85 // - if no value is present, you use None |
84 |
86 |
85 |
87 |
86 List(7,2,3,4,5,6).find(_ < 4) |
88 List(7,24,3,4,5,6).find(_ < 4) |
87 List(5,6,7,8,9).find(_ < 4) |
89 List(5,6,7,8,9).find(_ < 4) |
88 |
90 |
|
91 List(7,2,3,4,5,6).filter(_ < 4) |
89 |
92 |
90 // some operations on Option's |
93 // some operations on Option's |
91 |
94 |
92 val lst = List(None, Some(1), Some(2), None, Some(3)) |
95 val lst = List(None, Some(1), Some(2), None, Some(3)) |
93 |
96 |
94 lst.flatten |
97 lst.flatten |
95 |
98 |
96 Some(1).get |
99 Some(10).get |
|
100 None.get |
97 |
101 |
98 Some(1).isDefined |
102 Some(1).isDefined |
99 None.isDefined |
103 None.isDefined |
100 |
104 |
101 val ps = List((3, 0), (3, 2), (4, 2), (2, 0), (1, 0), (1, 1)) |
105 val ps = List((3, 0), (3, 2), (4, 2), (2, 0), (1, 0), (1, 1)) |
165 // code could potentially throw a NullPointerException. |
170 // code could potentially throw a NullPointerException. |
166 |
171 |
167 |
172 |
168 // even Scala is not immune to problems like this: |
173 // even Scala is not immune to problems like this: |
169 |
174 |
170 List(5,6,7,8,9).indexOf(7) |
175 List(5,6,7,8,9).indexOf(42) |
171 |
176 |
172 |
177 |
|
178 // ... how are we supposed to know that this returns -1 |
173 |
179 |
174 |
180 |
175 // Higher-Order Functions |
181 // Higher-Order Functions |
176 //======================== |
182 //======================== |
177 |
183 |
180 val lst = (1 to 10).toList |
186 val lst = (1 to 10).toList |
181 |
187 |
182 def even(x: Int) : Boolean = x % 2 == 0 |
188 def even(x: Int) : Boolean = x % 2 == 0 |
183 def odd(x: Int) : Boolean = x % 2 == 1 |
189 def odd(x: Int) : Boolean = x % 2 == 1 |
184 |
190 |
185 lst.filter(x => even(x)) |
191 lst.filter(x => even(x) && odd(x)) |
186 lst.filter(even(_)) |
192 lst.filter(even(_)) |
187 lst.filter(even) |
193 lst.filter(odd && even) |
188 |
194 |
189 lst.find(_ > 8) |
195 lst.find(_ > 8) |
190 |
196 |
191 // map applies a function to each element of a list |
197 // map applies a function to each element of a list |
192 |
198 |
193 def square(x: Int): Int = x * x |
199 def square(x: Int): Int = x * x |
194 |
200 |
|
201 val lst = (1 to 10).toList |
195 lst.map(square) |
202 lst.map(square) |
196 |
203 |
197 lst.map(square).filter(_ > 4) |
204 lst.map(square).filter(_ > 4) |
198 |
205 |
199 lst.map(square).filter(_ > 4).map(square) |
206 lst.map(square).filter(_ > 4).map(square) |
200 |
207 |
201 // map works for most collection types, including sets |
208 // map works for most collection types, including sets |
202 Set(1, 3, 6).map(square) |
209 Set(1, 3, 6).map(square).filter(_ > 4) |
203 |
210 |
204 |
211 |
205 // Why could functions as arguments be useful? |
212 val l = List((1, 3),(2, 4),(4, 1),(6, 2)) |
|
213 |
|
214 l.map(square(_._1)) |
|
215 |
|
216 |
|
217 // Why are functions as arguments useful? |
206 // |
218 // |
207 // Consider the sum between a and b: |
219 // Consider the sum between a and b: |
208 |
220 |
209 def sumInts(a: Int, b: Int) : Int = |
221 def sumInts(a: Int, b: Int) : Int = |
210 if (a > b) 0 else a + sumInts(a + 1, b) |
222 if (a > b) 0 else a + sumInts(a + 1, b) |
211 |
223 |
212 |
224 |
213 sumInt(10, 16) |
225 sumInts(10, 16) |
214 |
226 |
215 // sum squares |
227 // sum squares |
216 def square(n: Int) : Int = n * n |
228 def square(n: Int) : Int = n * n |
217 |
229 |
218 def sumSquares(a: Int, b: Int) : Int = |
230 def sumSquares(a: Int, b: Int) : Int = |
230 |
242 |
231 sumFacts(2, 6) |
243 sumFacts(2, 6) |
232 |
244 |
233 |
245 |
234 |
246 |
235 // You can see the pattern....can we simplify out work? |
247 // You can see the pattern....can we simplify our work? |
236 // The type of functions from ints to ints: Int => Int |
248 // The type of functions from ints to ints: Int => Int |
237 |
249 |
238 def sum(f: Int => Int, a: Int, b: Int) : Int = { |
250 def sum(f: Int => Int, a: Int, b: Int) : Int = { |
239 if (a > b) 0 |
251 if (a > b) 0 |
240 else f(a) + sum(f, a + 1, b) |
252 else f(a) + sum(f, a + 1, b) |
247 // What should we do for sumInts? |
259 // What should we do for sumInts? |
248 |
260 |
249 def id(n: Int) : Int = n |
261 def id(n: Int) : Int = n |
250 def sumInts(a: Int, b: Int) : Int = sum(id, a, b) |
262 def sumInts(a: Int, b: Int) : Int = sum(id, a, b) |
251 |
263 |
|
264 sumInts(10, 12) |
252 |
265 |
253 |
266 |
254 // Anonymous Functions: You can also write: |
267 // Anonymous Functions: You can also write: |
255 |
268 |
256 def sumCubes(a: Int, b: Int) : Int = sum(x => x * x * x, a, b) |
269 def sumCubes(a: Int, b: Int) : Int = sum(x => x * x * x, a, b) |
266 |
279 |
267 |
280 |
268 // an aside: partial application |
281 // an aside: partial application |
269 |
282 |
270 def add(a: Int)(b: Int) : Int = a + b |
283 def add(a: Int)(b: Int) : Int = a + b |
|
284 def add_abc(a: Int)(b: Int)(c: Int) : Int = a + b + c |
|
285 |
|
286 val add2 : Int => Int = add(2) |
|
287 add2(5) |
|
288 |
|
289 val add2_bc : Int => Int => Int = add_abc(2) |
|
290 val add2_9_c : Int => Int = add2_bc(9) |
|
291 |
|
292 add2_9_c(10) |
271 |
293 |
272 sum(add(2), 0, 2) |
294 sum(add(2), 0, 2) |
273 sum(add(10), 0, 2) |
295 sum(add(10), 0, 2) |
274 |
296 |
275 def add2(a: Int, b: Int) : Int = a + b |
|
276 sum(x => add2(2, x), 0, 2) |
|
277 sum(x => add2(10, x), 0, 2) |
|
278 |
297 |
279 // Function Composition |
298 // Function Composition |
280 //====================== |
299 //====================== |
281 |
300 |
282 // How could Higher-Order Functions and Options be helpful? |
301 // How can be Higher-Order Functions and Options be helpful? |
283 |
302 |
284 def add_footer(msg: String) : String = msg ++ " - Sent from iOS" |
303 def add_footer(msg: String) : String = msg ++ " - Sent from iOS" |
285 |
304 |
286 def valid_msg(msg: String) : Boolean = msg.size <= 140 |
305 def valid_msg(msg: String) : Boolean = msg.size <= 140 |
287 |
306 |
288 def duplicate(s: String) : String = s ++ s |
307 def duplicate(s: String) : String = s ++ s |
289 |
308 |
290 // they compose nicely |
309 // they compose very nicely, e.g |
|
310 |
291 valid_msg(add_footer("Hello World")) |
311 valid_msg(add_footer("Hello World")) |
292 valid_msg(duplicate(add_footer("Hello World"))) |
312 valid_msg(duplicate(duplicate(add_footer("Helloooooooooooooooooo World")))) |
293 |
313 |
294 |
314 // but not all functions do |
295 // first_word: let's first do it the ugly Java way using null: |
315 // first_word: let's first do it the ugly Java way using null: |
296 |
316 |
297 def first_word(msg: String) : String = { |
317 def first_word(msg: String) : String = { |
298 val words = msg.split(" ") |
318 val words = msg.split(" ") |
299 if (words(0) != "") words(0) else null |
319 if (words(0) != "") words(0) else null |
304 |
324 |
305 def extended_duplicate(s: String) : String = |
325 def extended_duplicate(s: String) : String = |
306 if (s != null) s ++ s else null |
326 if (s != null) s ++ s else null |
307 |
327 |
308 extended_duplicate(first_word("")) |
328 extended_duplicate(first_word("")) |
|
329 |
|
330 // but this is against the rules of the game: we do not want |
|
331 // to change duplicate, because first_word might return null |
309 |
332 |
310 |
333 |
311 // Avoid always null! |
334 // Avoid always null! |
312 def better_first_word(msg: String) : Option[String] = { |
335 def better_first_word(msg: String) : Option[String] = { |
313 val words = msg.split(" ") |
336 val words = msg.split(" ") |
314 if (words(0) != "") Some(words(0)) else None |
337 if (words(0) != "") Some(words(0)) else None |
315 } |
338 } |
316 |
339 |
317 better_first_word("Hello World").map(duplicate) |
340 better_first_word("Hello World").map(duplicate) |
318 better_first_word("Hello World").map(duplicate).map(duplicate).map(valid_msg) |
341 |
|
342 better_first_word("Hello World").map(duplicate) |
|
343 better_first_word("").map(duplicate).map(duplicate).map(valid_msg) |
319 |
344 |
320 better_first_word("").map(duplicate) |
345 better_first_word("").map(duplicate) |
321 better_first_word("").map(duplicate).map(valid_msg) |
346 better_first_word("").map(duplicate).map(valid_msg) |
322 |
|
323 |
|
324 |
|
325 |
|
326 |
|
327 |
|
328 // Implicits (Cool Feature) |
|
329 //========================= |
|
330 // |
|
331 // For example adding your own methods to Strings: |
|
332 // Imagine you want to increment strings, like |
|
333 // |
|
334 // "HAL".increment |
|
335 // |
|
336 // you can avoid ugly fudges, like a MyString, by |
|
337 // using implicit conversions. |
|
338 |
|
339 |
|
340 implicit class MyString(s: String) { |
|
341 def increment = for (c <- s) yield (c + 1).toChar |
|
342 } |
|
343 |
|
344 "HAL".increment |
|
345 |
|
346 |
|
347 |
|
348 // No returns in Scala |
|
349 //==================== |
|
350 |
|
351 // You should not use "return" in Scala: |
|
352 // |
|
353 // A return expression, when evaluated, abandons the |
|
354 // current computation and returns to the caller of the |
|
355 // function in which return appears." |
|
356 |
|
357 def sq1(x: Int): Int = x * x |
|
358 def sq2(x: Int): Int = return x * x |
|
359 |
|
360 def sumq(ls: List[Int]): Int = { |
|
361 ls.map(sq1).sum[Int] |
|
362 } |
|
363 |
|
364 sumq(List(1, 2, 3, 4)) |
|
365 |
|
366 |
|
367 |
|
368 def sumq(ls: List[Int]): Int = { |
|
369 val sqs : List[Int] = for (x <- ls) yield (return x * x) |
|
370 sqs.sum |
|
371 } |
|
372 |
|
373 |
|
374 |
347 |
375 |
348 |
376 // Pattern Matching |
349 // Pattern Matching |
377 //================== |
350 //================== |
378 |
351 |
447 case Green() => true |
420 case Green() => true |
448 case Blue() => false |
421 case Blue() => false |
449 } |
422 } |
450 |
423 |
451 |
424 |
452 // actually this can be written with "object" |
425 // actually colors can be written with "object", |
|
426 // because they do not take any arguments |
453 |
427 |
454 |
428 |
455 // another example |
429 // another example |
456 //================= |
430 //================= |
|
431 |
|
432 // Once upon a time, in a complete fictional country there were persons... |
457 |
433 |
458 abstract class Person |
434 abstract class Person |
459 case class King() extends Person |
435 case class King() extends Person |
460 case class Peer(deg: String, terr: String, succ: Int) extends Person |
436 case class Peer(deg: String, terr: String, succ: Int) extends Person |
461 case class Knight(name: String) extends Person |
437 case class Knight(name: String) extends Person |
506 val A = (1 to 1000).toSet |
481 val A = (1 to 1000).toSet |
507 val B = (1 to 1000 by 4).toSet |
482 val B = (1 to 1000 by 4).toSet |
508 |
483 |
509 count_intersection(A, B) |
484 count_intersection(A, B) |
510 |
485 |
511 // but do not try to add .par to the for-loop above |
486 // but do not try to add .par to the for-loop above, |
|
487 // otherwise you will be caught in race-condition hell. |
512 |
488 |
513 |
489 |
514 //propper parallel version |
490 //propper parallel version |
515 def count_intersection2(A: Set[Int], B: Set[Int]) : Int = |
491 def count_intersection2(A: Set[Int], B: Set[Int]) : Int = |
516 A.par.count(x => B contains x) |
492 A.par.count(x => B contains x) |
531 |
507 |
532 time_needed(10, count_intersection(A, B)) |
508 time_needed(10, count_intersection(A, B)) |
533 time_needed(10, count_intersection2(A, B)) |
509 time_needed(10, count_intersection2(A, B)) |
534 |
510 |
535 |
511 |
|
512 // Implicits (Cool Feature) |
|
513 //========================= |
|
514 // |
|
515 // For example adding your own methods to Strings: |
|
516 // Imagine you want to increment strings, like |
|
517 // |
|
518 // "HAL".increment |
|
519 // |
|
520 // you can avoid ugly fudges, like a MyString, by |
|
521 // using implicit conversions. |
|
522 |
|
523 |
|
524 implicit class MyString(s: String) { |
|
525 def increment = for (c <- s) yield (c + 1).toChar |
|
526 } |
|
527 |
|
528 "HAL".increment |
|
529 |
|
530 |
|
531 |
|
532 // No returns in Scala |
|
533 //==================== |
|
534 |
|
535 // You should not use "return" in Scala: |
|
536 // |
|
537 // A return expression, when evaluated, abandons the |
|
538 // current computation and returns to the caller of the |
|
539 // function in which return appears." |
|
540 |
|
541 def sq1(x: Int): Int = x * x |
|
542 def sq2(x: Int): Int = return x * x |
|
543 |
|
544 def sumq(ls: List[Int]): Int = { |
|
545 ls.map(sq1).sum[Int] |
|
546 } |
|
547 |
|
548 sumq(List(1, 2, 3, 4)) |
|
549 |
|
550 |
|
551 |
|
552 def sumq(ls: List[Int]): Int = { |
|
553 val sqs : List[Int] = for (x <- ls) yield (return x * x) |
|
554 sqs.sum |
|
555 } |
|
556 |
|
557 |
|
558 |
|
559 |
536 // Type abbreviations |
560 // Type abbreviations |
537 //==================== |
561 //==================== |
538 |
562 |
539 // some syntactic convenience |
563 // some syntactic convenience |
540 |
564 |
570 val indexes = (0 to 8).toList |
594 val indexes = (0 to 8).toList |
571 |
595 |
572 |
596 |
573 def empty(game: String) = game.indexOf(EmptyValue) |
597 def empty(game: String) = game.indexOf(EmptyValue) |
574 def isDone(game: String) = empty(game) == -1 |
598 def isDone(game: String) = empty(game) == -1 |
575 def emptyPosition(game: String) = (empty(game) % MaxValue, empty(game) / MaxValue) |
599 def emptyPosition(game: String) = |
576 |
600 (empty(game) % MaxValue, empty(game) / MaxValue) |
577 |
601 |
578 def get_row(game: String, y: Int) = indexes.map(col => game(y * MaxValue + col)) |
602 |
579 def get_col(game: String, x: Int) = indexes.map(row => game(x + row * MaxValue)) |
603 def get_row(game: String, y: Int) = |
|
604 indexes.map(col => game(y * MaxValue + col)) |
|
605 def get_col(game: String, x: Int) = |
|
606 indexes.map(row => game(x + row * MaxValue)) |
580 |
607 |
581 get_row(game0, 3) |
608 get_row(game0, 3) |
582 get_col(game0, 0) |
609 get_col(game0, 0) |
583 |
610 |
584 def get_box(game: String, pos: Pos): List[Char] = { |
611 def get_box(game: String, pos: Pos): List[Char] = { |
592 get_box(game0, (0, 0)) |
619 get_box(game0, (0, 0)) |
593 get_box(game0, (1, 1)) |
620 get_box(game0, (1, 1)) |
594 get_box(game0, (2, 1)) |
621 get_box(game0, (2, 1)) |
595 |
622 |
596 // this is not mutable!! |
623 // this is not mutable!! |
597 def update(game: String, pos: Int, value: Char): String = game.updated(pos, value) |
624 def update(game: String, pos: Int, value: Char): String = |
|
625 game.updated(pos, value) |
598 |
626 |
599 def toAvoid(game: String, pos: Pos): List[Char] = |
627 def toAvoid(game: String, pos: Pos): List[Char] = |
600 (get_col(game, pos._1) ++ get_row(game, pos._2) ++ get_box(game, pos)) |
628 (get_col(game, pos._1) ++ get_row(game, pos._2) ++ get_box(game, pos)) |
601 |
629 |
602 def candidates(game: String, pos: Pos): List[Char] = allValues.diff(toAvoid(game,pos)) |
630 def candidates(game: String, pos: Pos): List[Char] = |
|
631 allValues.diff(toAvoid(game,pos)) |
603 |
632 |
604 //candidates(game0, (0,0)) |
633 //candidates(game0, (0,0)) |
605 |
634 |
606 def pretty(game: String): String = |
635 def pretty(game: String): String = |
607 "\n" + (game sliding (MaxValue, MaxValue) mkString "\n") |
636 "\n" + (game sliding (MaxValue, MaxValue) mkString "\n") |
608 |
637 |
609 def search(game: String): List[String] = { |
638 def search(game: String): List[String] = { |
610 if (isDone(game)) List(game) |
639 if (isDone(game)) List(game) |
611 else { |
640 else { |
612 val cs = candidates(game, emptyPosition(game)) |
641 val cs = candidates(game, emptyPosition(game)) |
613 cs.map(c => search(update(game, empty(game), c))).toList.flatten |
642 cs.par.map(c => search(update(game, empty(game), c))).toList.flatten |
614 } |
643 } |
615 } |
644 } |
616 |
645 |
617 search(game0).map(pretty) |
646 search(game0).map(pretty) |
618 |
647 |