| 51 |      1 | // Scala Lecture 2
 | 
|  |      2 | //=================
 | 
|  |      3 | 
 | 
|  |      4 | 
 | 
| 148 |      5 | // the pain with overloaded math operations
 | 
| 147 |      6 | 
 | 
|  |      7 | (100 / 4)
 | 
|  |      8 | 
 | 
|  |      9 | (100 / 3)
 | 
|  |     10 | 
 | 
|  |     11 | (100.toDouble / 3.toDouble)
 | 
|  |     12 | 
 | 
|  |     13 | 
 | 
|  |     14 | // For-Comprehensions again
 | 
|  |     15 | //==========================
 | 
|  |     16 | 
 | 
|  |     17 | def square(n: Int) : Int = n * n
 | 
|  |     18 | 
 | 
|  |     19 | for (n <- (1 to 10).toList) yield {
 | 
|  |     20 |   val res = square(n)
 | 
|  |     21 |   res
 | 
|  |     22 | }
 | 
|  |     23 | 
 | 
|  |     24 | // like in functions, the "last" item inside the yield
 | 
|  |     25 | // will be returned; the last item is not necessarily 
 | 
|  |     26 | // the last line
 | 
|  |     27 | 
 | 
|  |     28 | for (n <- (1 to 10).toList) yield {
 | 
|  |     29 |   if (n % 2 == 0) n 
 | 
|  |     30 |   else square(n)
 | 
|  |     31 | }
 | 
|  |     32 | 
 | 
|  |     33 | 
 | 
|  |     34 | // ...please, please do not write:
 | 
|  |     35 | val lst = List(1, 2, 3, 4, 5, 6, 7, 8, 9)
 | 
|  |     36 | 
 | 
|  |     37 | for (i <- (0 until lst.length).toList) yield square(lst(i))
 | 
|  |     38 | 
 | 
|  |     39 | // this is just so prone to off-by-one errors;
 | 
|  |     40 | // write instead
 | 
|  |     41 | 
 | 
| 150 |     42 | for (e <- lst; if (e % 2) == 0; if (e != 4)) yield square(e)
 | 
| 147 |     43 | 
 | 
|  |     44 | 
 | 
|  |     45 | //this works for sets as well
 | 
|  |     46 | val st = Set(1, 2, 3, 4, 5, 6, 7, 8, 9)
 | 
|  |     47 | 
 | 
|  |     48 | for (e <- st) yield {
 | 
|  |     49 |   if (e < 5) e else square(e)
 | 
|  |     50 | }
 | 
|  |     51 | 
 | 
|  |     52 | 
 | 
|  |     53 | 
 | 
|  |     54 | // Side-Effects
 | 
|  |     55 | //==============
 | 
|  |     56 | 
 | 
|  |     57 | // with only a side-effect (no list is produced),
 | 
| 150 |     58 | // for has no "yield"
 | 
| 147 |     59 | 
 | 
|  |     60 | for (n <- (1 to 10)) println(n)
 | 
|  |     61 | 
 | 
|  |     62 | 
 | 
|  |     63 | for (n <- (1 to 10)) {
 | 
|  |     64 |   print("The number is: ")
 | 
|  |     65 |   print(n)
 | 
|  |     66 |   print("\n")
 | 
|  |     67 | }
 | 
|  |     68 | 
 | 
|  |     69 | 
 | 
|  |     70 | 
 | 
|  |     71 | 
 | 
|  |     72 | // know when to use yield and when not:
 | 
|  |     73 | 
 | 
| 150 |     74 | val test = 
 | 
|  |     75 |  for (e <- Set(1, 2, 3, 4, 5, 6, 7, 8, 9); if e < 5) yield square(e)
 | 
|  |     76 | 
 | 
| 147 |     77 | 
 | 
|  |     78 | 
 | 
| 51 |     79 | // Option type
 | 
|  |     80 | //=============
 | 
| 53 |     81 | 
 | 
| 147 |     82 | //in Java, if something unusually happens, you return null;
 | 
| 53 |     83 | //in Scala you use Option
 | 
|  |     84 | //   - if the value is present, you use Some(value)
 | 
|  |     85 | //   - if no value is present, you use None
 | 
|  |     86 | 
 | 
|  |     87 | 
 | 
| 150 |     88 | List(7,24,3,4,5,6).find(_ < 4)
 | 
| 53 |     89 | List(5,6,7,8,9).find(_ < 4)
 | 
|  |     90 | 
 | 
| 150 |     91 | List(7,2,3,4,5,6).filter(_ < 4)
 | 
| 58 |     92 | 
 | 
| 147 |     93 | // some operations on Option's
 | 
| 58 |     94 | 
 | 
| 51 |     95 | val lst = List(None, Some(1), Some(2), None, Some(3))
 | 
|  |     96 | 
 | 
|  |     97 | lst.flatten
 | 
| 53 |     98 | 
 | 
| 150 |     99 | Some(10).get
 | 
|  |    100 | None.get
 | 
| 51 |    101 | 
 | 
| 53 |    102 | Some(1).isDefined
 | 
|  |    103 | None.isDefined
 | 
|  |    104 | 
 | 
| 51 |    105 | val ps = List((3, 0), (3, 2), (4, 2), (2, 0), (1, 0), (1, 1))
 | 
|  |    106 | 
 | 
|  |    107 | for ((x, y) <- ps) yield {
 | 
|  |    108 |   if (y == 0) None else Some(x / y)
 | 
|  |    109 | }
 | 
|  |    110 | 
 | 
| 147 |    111 | // use .getOrElse is for setting a default value
 | 
| 53 |    112 | 
 | 
|  |    113 | val lst = List(None, Some(1), Some(2), None, Some(3))
 | 
| 147 |    114 | 
 | 
| 57 |    115 | for (x <- lst) yield x.getOrElse(0)
 | 
|  |    116 | 
 | 
|  |    117 | 
 | 
| 53 |    118 | 
 | 
|  |    119 | 
 | 
| 147 |    120 | // error handling with Options (no exceptions)
 | 
|  |    121 | //
 | 
|  |    122 | //  Try(....)
 | 
| 57 |    123 | //
 | 
|  |    124 | //  Try(something).getOrElse(what_to_do_in_an_exception)
 | 
|  |    125 | //
 | 
| 53 |    126 | import scala.util._
 | 
| 147 |    127 | 
 | 
|  |    128 | Try(1 + 3)
 | 
|  |    129 | Try(9 / 0) 
 | 
|  |    130 | 
 | 
|  |    131 | Try(9 / 3).getOrElse(42) 
 | 
|  |    132 | Try(9 / 0).getOrElse(42) 
 | 
|  |    133 | 
 | 
|  |    134 | 
 | 
| 53 |    135 | import io.Source
 | 
|  |    136 | 
 | 
| 147 |    137 | val my_url = """https://nms.kcl.ac.uk/christian.urban"""
 | 
| 150 |    138 | //val my_url = """https://nms.kcl.ac.uk/christan.urban"""  // misspelled
 | 
| 147 |    139 | 
 | 
|  |    140 | Source.fromURL(my_url).mkString
 | 
| 53 |    141 | 
 | 
| 147 |    142 | Try(Source.fromURL(my_url).mkString).getOrElse("")
 | 
| 53 |    143 | 
 | 
| 147 |    144 | Try(Some(Source.fromURL(my_url).mkString)).getOrElse(None)
 | 
|  |    145 | 
 | 
| 53 |    146 | 
 | 
| 57 |    147 | // a function that turns strings into numbers
 | 
| 147 |    148 | Integer.parseInt("1234")
 | 
|  |    149 | 
 | 
| 53 |    150 | 
 | 
|  |    151 | def get_me_an_int(s: String): Option[Int] = 
 | 
|  |    152 |  Try(Some(Integer.parseInt(s))).getOrElse(None)
 | 
|  |    153 | 
 | 
|  |    154 | val lst = List("12345", "foo", "5432", "bar", "x21")
 | 
| 147 |    155 | 
 | 
| 53 |    156 | for (x <- lst) yield get_me_an_int(x)
 | 
|  |    157 | 
 | 
|  |    158 | // summing all the numbers
 | 
| 147 |    159 | val sum = (for (i <- lst) yield get_me_an_int(i)).flatten.sum
 | 
| 53 |    160 | 
 | 
|  |    161 | 
 | 
|  |    162 | // This may not look any better than working with null in Java, but to
 | 
|  |    163 | // see the value, you have to put yourself in the shoes of the
 | 
|  |    164 | // consumer of the get_me_an_int function, and imagine you didn't
 | 
|  |    165 | // write that function.
 | 
|  |    166 | //
 | 
|  |    167 | // In Java, if you didn't write this function, you'd have to depend on
 | 
| 147 |    168 | // the Javadoc of get_me_an_int. If you didn't look at the Javadoc, 
 | 
| 57 |    169 | // you might not know that get_me_an_int could return a null, and your 
 | 
|  |    170 | // code could potentially throw a NullPointerException.
 | 
| 53 |    171 | 
 | 
|  |    172 | 
 | 
| 58 |    173 | // even Scala is not immune to problems like this:
 | 
|  |    174 | 
 | 
| 150 |    175 | List(5,6,7,8,9).indexOf(42)
 | 
| 58 |    176 | 
 | 
|  |    177 | 
 | 
| 150 |    178 | // ... how are we supposed to know that this returns -1
 | 
| 58 |    179 | 
 | 
|  |    180 | 
 | 
| 147 |    181 | // Higher-Order Functions
 | 
|  |    182 | //========================
 | 
|  |    183 | 
 | 
|  |    184 | // functions can take functions as arguments
 | 
|  |    185 | 
 | 
|  |    186 | val lst = (1 to 10).toList
 | 
|  |    187 | 
 | 
|  |    188 | def even(x: Int) : Boolean = x % 2 == 0
 | 
|  |    189 | def odd(x: Int) : Boolean = x % 2 == 1
 | 
|  |    190 | 
 | 
| 150 |    191 | lst.filter(x => even(x) && odd(x))
 | 
| 147 |    192 | lst.filter(even(_))
 | 
| 150 |    193 | lst.filter(odd && even)
 | 
| 147 |    194 | 
 | 
|  |    195 | lst.find(_ > 8)
 | 
|  |    196 | 
 | 
|  |    197 | // map applies a function to each element of a list
 | 
|  |    198 | 
 | 
|  |    199 | def square(x: Int): Int = x * x
 | 
|  |    200 | 
 | 
| 150 |    201 | val lst = (1 to 10).toList
 | 
| 147 |    202 | lst.map(square)
 | 
|  |    203 | 
 | 
|  |    204 | lst.map(square).filter(_ > 4)
 | 
|  |    205 | 
 | 
|  |    206 | lst.map(square).filter(_ > 4).map(square)
 | 
|  |    207 | 
 | 
|  |    208 | // map works for most collection types, including sets
 | 
| 150 |    209 | Set(1, 3, 6).map(square).filter(_ > 4)
 | 
| 147 |    210 | 
 | 
|  |    211 | 
 | 
| 150 |    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?
 | 
| 147 |    218 | //
 | 
|  |    219 | // Consider the sum between a and b:
 | 
|  |    220 | 
 | 
|  |    221 | def sumInts(a: Int, b: Int) : Int = 
 | 
|  |    222 |   if (a > b) 0 else a + sumInts(a + 1, b)
 | 
|  |    223 | 
 | 
|  |    224 | 
 | 
| 150 |    225 | sumInts(10, 16)
 | 
| 147 |    226 | 
 | 
|  |    227 | // sum squares
 | 
|  |    228 | def square(n: Int) : Int = n * n
 | 
|  |    229 | 
 | 
|  |    230 | def sumSquares(a: Int, b: Int) : Int = 
 | 
|  |    231 |   if (a > b) 0 else square(a) + sumSquares(a + 1, b)
 | 
|  |    232 | 
 | 
|  |    233 | sumSquares(2, 6)
 | 
|  |    234 | 
 | 
|  |    235 | 
 | 
|  |    236 | // sum factorials
 | 
|  |    237 | def fact(n: Int) : Int =  
 | 
|  |    238 |   if (n == 0) 1 else n * fact(n - 1)
 | 
|  |    239 | 
 | 
|  |    240 | def sumFacts(a: Int, b: Int) : Int = 
 | 
|  |    241 |   if (a > b) 0 else fact(a) + sumFacts(a + 1, b)
 | 
|  |    242 | 
 | 
|  |    243 | sumFacts(2, 6)
 | 
|  |    244 | 
 | 
|  |    245 | 
 | 
|  |    246 | 
 | 
| 150 |    247 | // You can see the pattern....can we simplify our work?
 | 
| 147 |    248 | // The type of functions from ints to ints: Int => Int
 | 
|  |    249 | 
 | 
|  |    250 | def sum(f: Int => Int, a: Int, b: Int) : Int = {
 | 
|  |    251 |   if (a > b) 0 
 | 
|  |    252 |   else f(a) + sum(f, a + 1, b)
 | 
|  |    253 | }
 | 
|  |    254 | 
 | 
|  |    255 | 
 | 
|  |    256 | def sumSquares(a: Int, b: Int) : Int = sum(square, a, b)
 | 
|  |    257 | def sumFacts(a: Int, b: Int) : Int = sum(fact, a, b)
 | 
|  |    258 | 
 | 
|  |    259 | // What should we do for sumInts?
 | 
|  |    260 | 
 | 
|  |    261 | def id(n: Int) : Int = n
 | 
|  |    262 | def sumInts(a: Int, b: Int) : Int = sum(id, a, b)
 | 
|  |    263 | 
 | 
| 150 |    264 | sumInts(10, 12)
 | 
| 147 |    265 | 
 | 
|  |    266 | 
 | 
|  |    267 | // Anonymous Functions: You can also write:
 | 
|  |    268 | 
 | 
|  |    269 | def sumCubes(a: Int, b: Int) : Int =   sum(x => x * x * x, a, b)
 | 
|  |    270 | def sumSquares(a: Int, b: Int) : Int = sum(x => x * x, a, b)
 | 
|  |    271 | def sumInts(a: Int, b: Int) : Int    = sum(x => x, a, b)
 | 
|  |    272 | 
 | 
|  |    273 | 
 | 
|  |    274 | // other function types
 | 
|  |    275 | //
 | 
|  |    276 | // f1: (Int, Int) => Int
 | 
|  |    277 | // f2: List[String] => Option[Int]
 | 
|  |    278 | // ... 
 | 
|  |    279 | 
 | 
|  |    280 | 
 | 
| 148 |    281 | // an aside: partial application
 | 
|  |    282 | 
 | 
|  |    283 | def add(a: Int)(b: Int) : Int = a + b
 | 
| 150 |    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)
 | 
| 148 |    293 | 
 | 
|  |    294 | sum(add(2), 0, 2)
 | 
|  |    295 | sum(add(10), 0, 2)
 | 
|  |    296 | 
 | 
|  |    297 | 
 | 
| 147 |    298 | // Function Composition
 | 
|  |    299 | //======================
 | 
|  |    300 | 
 | 
| 150 |    301 | // How can be Higher-Order Functions and Options be helpful?
 | 
| 147 |    302 | 
 | 
|  |    303 | def add_footer(msg: String) : String = msg ++ " - Sent from iOS"
 | 
|  |    304 | 
 | 
|  |    305 | def valid_msg(msg: String) : Boolean = msg.size <= 140
 | 
|  |    306 | 
 | 
|  |    307 | def duplicate(s: String) : String = s ++ s
 | 
|  |    308 | 
 | 
| 150 |    309 | // they compose very nicely, e.g
 | 
|  |    310 | 
 | 
| 147 |    311 | valid_msg(add_footer("Hello World"))
 | 
| 150 |    312 | valid_msg(duplicate(duplicate(add_footer("Helloooooooooooooooooo World"))))
 | 
| 147 |    313 | 
 | 
| 150 |    314 | // but not all functions do
 | 
| 147 |    315 | // first_word: let's first do it the ugly Java way using null:
 | 
|  |    316 | 
 | 
|  |    317 | def first_word(msg: String) : String = {
 | 
|  |    318 |   val words = msg.split(" ")
 | 
|  |    319 |   if (words(0) != "") words(0) else null
 | 
|  |    320 | }
 | 
|  |    321 | 
 | 
|  |    322 | duplicate(first_word("Hello World"))
 | 
|  |    323 | duplicate(first_word(""))
 | 
|  |    324 | 
 | 
|  |    325 | def extended_duplicate(s: String) : String = 
 | 
|  |    326 |   if (s != null) s ++ s else null
 | 
|  |    327 | 
 | 
|  |    328 | extended_duplicate(first_word(""))
 | 
|  |    329 | 
 | 
| 150 |    330 | // but this is against the rules of the game: we do not want
 | 
|  |    331 | // to change duplicate, because first_word might return null
 | 
|  |    332 | 
 | 
| 147 |    333 | 
 | 
|  |    334 | // Avoid always null!
 | 
|  |    335 | def better_first_word(msg: String) : Option[String] = {
 | 
|  |    336 |   val words = msg.split(" ")
 | 
|  |    337 |   if (words(0) != "") Some(words(0)) else None
 | 
|  |    338 | }
 | 
|  |    339 | 
 | 
|  |    340 | better_first_word("Hello World").map(duplicate)
 | 
| 150 |    341 | 
 | 
|  |    342 | better_first_word("Hello World").map(duplicate)
 | 
|  |    343 | better_first_word("").map(duplicate).map(duplicate).map(valid_msg)
 | 
| 147 |    344 | 
 | 
|  |    345 | better_first_word("").map(duplicate)
 | 
|  |    346 | better_first_word("").map(duplicate).map(valid_msg)
 | 
|  |    347 | 
 | 
|  |    348 | 
 | 
| 150 |    349 | // Pattern Matching
 | 
|  |    350 | //==================
 | 
|  |    351 | 
 | 
|  |    352 | // A powerful tool which is supposed to come to Java in a few years
 | 
|  |    353 | // time (https://www.youtube.com/watch?v=oGll155-vuQ)...Scala already
 | 
|  |    354 | // has it for many years ;o)
 | 
|  |    355 | 
 | 
|  |    356 | // The general schema:
 | 
|  |    357 | //
 | 
|  |    358 | //    expression match {
 | 
|  |    359 | //       case pattern1 => expression1
 | 
|  |    360 | //       case pattern2 => expression2
 | 
|  |    361 | //       ...
 | 
|  |    362 | //       case patternN => expressionN
 | 
|  |    363 | //    }
 | 
|  |    364 | 
 | 
|  |    365 | 
 | 
|  |    366 | // remember
 | 
|  |    367 | val lst = List(None, Some(1), Some(2), None, Some(3)).flatten
 | 
|  |    368 | 
 | 
|  |    369 | 
 | 
|  |    370 | def my_flatten(xs: List[Option[Int]]): List[Int] = {
 | 
|  |    371 |   ...?
 | 
|  |    372 | }
 | 
|  |    373 | 
 | 
|  |    374 | 
 | 
|  |    375 | 
 | 
|  |    376 | 
 | 
|  |    377 | 
 | 
|  |    378 | def my_flatten(lst: List[Option[Int]]): List[Int] = lst match {
 | 
|  |    379 |   case Nil => Nil
 | 
|  |    380 |   case None::xs => my_flatten(xs)
 | 
|  |    381 |   case Some(n)::xs => n::my_flatten(xs)
 | 
|  |    382 | }
 | 
|  |    383 | 
 | 
|  |    384 | 
 | 
|  |    385 | // another example including a catch-all pattern
 | 
|  |    386 | def get_me_a_string(n: Int): String = n match {
 | 
|  |    387 |   case 0 => "zero"
 | 
|  |    388 |   case 1 => "one"
 | 
|  |    389 |   case 2 => "two"
 | 
|  |    390 |   case _ => "many"
 | 
|  |    391 | }
 | 
|  |    392 | 
 | 
|  |    393 | get_me_a_string(0)
 | 
|  |    394 | 
 | 
|  |    395 | // you can also have cases combined
 | 
|  |    396 | def season(month: String) = month match {
 | 
|  |    397 |   case "March" | "April" | "May" => "It's spring"
 | 
|  |    398 |   case "June" | "July" | "August" => "It's summer"
 | 
|  |    399 |   case "September" | "October" | "November" => "It's autumn"
 | 
|  |    400 |   case "December" | "January" | "February" => "It's winter"
 | 
|  |    401 | }
 | 
|  |    402 |  
 | 
|  |    403 | println(season("November"))
 | 
|  |    404 | 
 | 
|  |    405 | // What happens if no case matches?
 | 
|  |    406 | 
 | 
|  |    407 | println(season("foobar"))
 | 
|  |    408 | 
 | 
|  |    409 | 
 | 
|  |    410 | // User-defined Datatypes
 | 
|  |    411 | //========================
 | 
|  |    412 | 
 | 
|  |    413 | abstract class Colour
 | 
|  |    414 | case class Red() extends Colour 
 | 
|  |    415 | case class Green() extends Colour 
 | 
|  |    416 | case class Blue() extends Colour
 | 
|  |    417 | 
 | 
|  |    418 | def fav_colour(c: Colour) : Boolean = c match {
 | 
|  |    419 |   case Red()   => false
 | 
|  |    420 |   case Green() => true
 | 
|  |    421 |   case Blue()  => false 
 | 
|  |    422 | }
 | 
|  |    423 | 
 | 
|  |    424 | 
 | 
|  |    425 | // actually colors can be written with "object",
 | 
|  |    426 | // because they do not take any arguments
 | 
| 147 |    427 | 
 | 
| 58 |    428 | 
 | 
| 150 |    429 | // another example
 | 
|  |    430 | //=================
 | 
|  |    431 | 
 | 
|  |    432 | // Once upon a time, in a complete fictional country there were persons...
 | 
|  |    433 | 
 | 
|  |    434 | abstract class Person
 | 
|  |    435 | case class King() extends Person
 | 
|  |    436 | case class Peer(deg: String, terr: String, succ: Int) extends Person
 | 
|  |    437 | case class Knight(name: String) extends Person
 | 
|  |    438 | case class Peasant(name: String) extends Person
 | 
|  |    439 | 
 | 
|  |    440 | 
 | 
|  |    441 | def title(p: Person): String = p match {
 | 
|  |    442 |   case King() => "His Majesty the King"
 | 
|  |    443 |   case Peer(deg, terr, _) => s"The ${deg} of ${terr}"
 | 
|  |    444 |   case Knight(name) => s"Sir ${name}"
 | 
|  |    445 |   case Peasant(name) => name
 | 
|  |    446 | }
 | 
|  |    447 | 
 | 
|  |    448 | 
 | 
|  |    449 | def superior(p1: Person, p2: Person): Boolean = (p1, p2) match {
 | 
|  |    450 |   case (King(), _) => true
 | 
|  |    451 |   case (Peer(_,_,_), Knight(_)) => true
 | 
|  |    452 |   case (Peer(_,_,_), Peasant(_)) => true
 | 
|  |    453 |   case (Peer(_,_,_), Clown()) => true
 | 
|  |    454 |   case (Knight(_), Peasant(_)) => true
 | 
|  |    455 |   case (Knight(_), Clown()) => true
 | 
|  |    456 |   case (Clown(), Peasant(_)) => true
 | 
|  |    457 |   case _ => false
 | 
|  |    458 | }
 | 
|  |    459 | 
 | 
|  |    460 | val people = List(Knight("David"), 
 | 
|  |    461 |                   Peer("Duke", "Norfolk", 84), 
 | 
|  |    462 |                   Peasant("Christian"), 
 | 
|  |    463 |                   King(), 
 | 
|  |    464 |                   Clown())
 | 
|  |    465 | 
 | 
|  |    466 | println(people.sortWith(superior(_, _)).mkString(", "))
 | 
|  |    467 | 
 | 
|  |    468 | 
 | 
|  |    469 | 
 | 
|  |    470 | 
 | 
|  |    471 | 
 | 
|  |    472 | // Problems with mutability and parallel computations
 | 
|  |    473 | //====================================================
 | 
|  |    474 | 
 | 
|  |    475 | def count_intersection(A: Set[Int], B: Set[Int]) : Int = {
 | 
|  |    476 |   var count = 0
 | 
|  |    477 |   for (x <- A; if (B contains x)) count += 1 
 | 
|  |    478 |   count
 | 
|  |    479 | }
 | 
|  |    480 | 
 | 
|  |    481 | val A = (1 to 1000).toSet
 | 
|  |    482 | val B = (1 to 1000 by 4).toSet
 | 
|  |    483 | 
 | 
|  |    484 | count_intersection(A, B)
 | 
|  |    485 | 
 | 
|  |    486 | // but do not try to add .par to the for-loop above,
 | 
|  |    487 | // otherwise you will be caught in race-condition hell.
 | 
|  |    488 | 
 | 
|  |    489 | 
 | 
|  |    490 | //propper parallel version
 | 
|  |    491 | def count_intersection2(A: Set[Int], B: Set[Int]) : Int = 
 | 
|  |    492 |   A.par.count(x => B contains x)
 | 
|  |    493 | 
 | 
|  |    494 | count_intersection2(A, B)
 | 
|  |    495 | 
 | 
|  |    496 | 
 | 
|  |    497 | //for measuring time
 | 
|  |    498 | def time_needed[T](n: Int, code: => T) = {
 | 
|  |    499 |   val start = System.nanoTime()
 | 
|  |    500 |   for (i <- (0 to n)) code
 | 
|  |    501 |   val end = System.nanoTime()
 | 
|  |    502 |   (end - start) / 1.0e9
 | 
|  |    503 | }
 | 
|  |    504 | 
 | 
|  |    505 | val A = (1 to 1000000).toSet
 | 
|  |    506 | val B = (1 to 1000000 by 4).toSet
 | 
|  |    507 | 
 | 
|  |    508 | time_needed(10, count_intersection(A, B))
 | 
|  |    509 | time_needed(10, count_intersection2(A, B))
 | 
| 53 |    510 | 
 | 
|  |    511 | 
 | 
| 147 |    512 | // Implicits (Cool Feature)
 | 
|  |    513 | //=========================
 | 
| 57 |    514 | //
 | 
| 147 |    515 | // For example adding your own methods to Strings:
 | 
|  |    516 | // Imagine you want to increment strings, like
 | 
| 57 |    517 | //
 | 
|  |    518 | //     "HAL".increment
 | 
|  |    519 | //
 | 
|  |    520 | // you can avoid ugly fudges, like a MyString, by
 | 
| 147 |    521 | // using implicit conversions.
 | 
| 57 |    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 | 
 | 
| 147 |    531 | 
 | 
|  |    532 | // No returns in Scala
 | 
| 53 |    533 | //====================
 | 
|  |    534 | 
 | 
| 147 |    535 | // You should not use "return" in Scala:
 | 
| 53 |    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 = {
 | 
| 147 |    545 |   ls.map(sq1).sum[Int]
 | 
| 53 |    546 | }
 | 
|  |    547 | 
 | 
| 147 |    548 | sumq(List(1, 2, 3, 4))
 | 
| 36 |    549 | 
 | 
| 57 |    550 | 
 | 
| 147 |    551 | 
 | 
|  |    552 | def sumq(ls: List[Int]): Int = {
 | 
|  |    553 |   val sqs : List[Int] = for (x <- ls) yield (return x * x)
 | 
|  |    554 |   sqs.sum
 | 
| 53 |    555 | }
 | 
|  |    556 | 
 | 
| 55 |    557 | 
 | 
|  |    558 | 
 | 
| 147 |    559 | 
 | 
| 148 |    560 | // Type abbreviations
 | 
|  |    561 | //====================
 | 
|  |    562 | 
 | 
|  |    563 | // some syntactic convenience
 | 
|  |    564 | 
 | 
|  |    565 | type Pos = (int, Int)
 | 
|  |    566 | type Board = List[List[Int]]
 | 
|  |    567 | 
 | 
| 56 |    568 | 
 | 
| 57 |    569 | 
 | 
|  |    570 | 
 | 
| 150 |    571 | // Sudoku in Scala
 | 
|  |    572 | //=================
 | 
| 53 |    573 | 
 | 
| 57 |    574 | // THE POINT OF THIS CODE IS NOT TO BE SUPER
 | 
|  |    575 | // EFFICIENT AND FAST, just explaining exhaustive
 | 
|  |    576 | // depth-first search
 | 
|  |    577 | 
 | 
|  |    578 | 
 | 
| 55 |    579 | val game0 = """.14.6.3..
 | 
|  |    580 |               |62...4..9
 | 
|  |    581 |               |.8..5.6..
 | 
|  |    582 |               |.6.2....3
 | 
|  |    583 |               |.7..1..5.
 | 
|  |    584 |               |5....9.6.
 | 
|  |    585 |               |..6.2..3.
 | 
|  |    586 |               |1..5...92
 | 
|  |    587 |               |..7.9.41.""".stripMargin.replaceAll("\\n", "")
 | 
|  |    588 | 
 | 
|  |    589 | type Pos = (Int, Int)
 | 
|  |    590 | val EmptyValue = '.'
 | 
|  |    591 | val MaxValue = 9
 | 
|  |    592 | 
 | 
|  |    593 | val allValues = "123456789".toList
 | 
|  |    594 | val indexes = (0 to 8).toList
 | 
|  |    595 | 
 | 
| 57 |    596 | 
 | 
|  |    597 | def empty(game: String) = game.indexOf(EmptyValue)
 | 
|  |    598 | def isDone(game: String) = empty(game) == -1 
 | 
| 150 |    599 | def emptyPosition(game: String) = 
 | 
|  |    600 |   (empty(game) % MaxValue, empty(game) / MaxValue)
 | 
| 57 |    601 | 
 | 
| 55 |    602 | 
 | 
| 150 |    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))
 | 
| 57 |    607 | 
 | 
| 147 |    608 | get_row(game0, 3)
 | 
|  |    609 | get_col(game0, 0)
 | 
|  |    610 | 
 | 
| 57 |    611 | def get_box(game: String, pos: Pos): List[Char] = {
 | 
| 55 |    612 |     def base(p: Int): Int = (p / 3) * 3
 | 
|  |    613 |     val x0 = base(pos._1)
 | 
|  |    614 |     val y0 = base(pos._2)
 | 
|  |    615 |     val ys = (y0 until y0 + 3).toList
 | 
|  |    616 |     (x0 until x0 + 3).toList.flatMap(x => ys.map(y => game(x + y * MaxValue)))
 | 
|  |    617 | }
 | 
|  |    618 | 
 | 
| 147 |    619 | get_box(game0, (0, 0))
 | 
|  |    620 | get_box(game0, (1, 1))
 | 
|  |    621 | get_box(game0, (2, 1))
 | 
| 55 |    622 | 
 | 
| 147 |    623 | // this is not mutable!!
 | 
| 150 |    624 | def update(game: String, pos: Int, value: Char): String = 
 | 
|  |    625 |   game.updated(pos, value)
 | 
| 55 |    626 | 
 | 
|  |    627 | def toAvoid(game: String, pos: Pos): List[Char] = 
 | 
| 57 |    628 |   (get_col(game, pos._1) ++ get_row(game, pos._2) ++ get_box(game, pos))
 | 
| 55 |    629 | 
 | 
| 150 |    630 | def candidates(game: String, pos: Pos): List[Char] = 
 | 
|  |    631 |   allValues.diff(toAvoid(game,pos))
 | 
| 55 |    632 | 
 | 
|  |    633 | //candidates(game0, (0,0))
 | 
|  |    634 | 
 | 
| 147 |    635 | def pretty(game: String): String = 
 | 
|  |    636 |   "\n" + (game sliding (MaxValue, MaxValue) mkString "\n")
 | 
| 55 |    637 | 
 | 
|  |    638 | def search(game: String): List[String] = {
 | 
|  |    639 |   if (isDone(game)) List(game)
 | 
| 147 |    640 |   else {
 | 
|  |    641 |     val cs = candidates(game, emptyPosition(game))
 | 
| 150 |    642 |     cs.par.map(c => search(update(game, empty(game), c))).toList.flatten
 | 
| 147 |    643 |   }
 | 
| 55 |    644 | }
 | 
|  |    645 | 
 | 
| 147 |    646 | search(game0).map(pretty)
 | 
| 55 |    647 | 
 | 
|  |    648 | val game1 = """23.915...
 | 
|  |    649 |               |...2..54.
 | 
|  |    650 |               |6.7......
 | 
|  |    651 |               |..1.....9
 | 
|  |    652 |               |89.5.3.17
 | 
|  |    653 |               |5.....6..
 | 
|  |    654 |               |......9.5
 | 
|  |    655 |               |.16..7...
 | 
|  |    656 |               |...329..1""".stripMargin.replaceAll("\\n", "")
 | 
|  |    657 | 
 | 
| 147 |    658 | search(game1).map(pretty)
 | 
| 57 |    659 | 
 | 
| 147 |    660 | // game that is in the hard(er) category
 | 
| 55 |    661 | val game2 = """8........
 | 
|  |    662 |               |..36.....
 | 
|  |    663 |               |.7..9.2..
 | 
|  |    664 |               |.5...7...
 | 
|  |    665 |               |....457..
 | 
|  |    666 |               |...1...3.
 | 
|  |    667 |               |..1....68
 | 
|  |    668 |               |..85...1.
 | 
|  |    669 |               |.9....4..""".stripMargin.replaceAll("\\n", "")
 | 
|  |    670 | 
 | 
|  |    671 | // game with multiple solutions
 | 
|  |    672 | val game3 = """.8...9743
 | 
|  |    673 |               |.5...8.1.
 | 
|  |    674 |               |.1.......
 | 
|  |    675 |               |8....5...
 | 
|  |    676 |               |...8.4...
 | 
|  |    677 |               |...3....6
 | 
|  |    678 |               |.......7.
 | 
|  |    679 |               |.3.5...8.
 | 
|  |    680 |               |9724...5.""".stripMargin.replaceAll("\\n", "")
 | 
|  |    681 | 
 | 
| 57 |    682 | 
 | 
| 147 |    683 | search(game2).map(pretty)
 | 
|  |    684 | search(game3).map(pretty)
 | 
| 55 |    685 | 
 | 
|  |    686 | // for measuring time
 | 
|  |    687 | def time_needed[T](i: Int, code: => T) = {
 | 
|  |    688 |   val start = System.nanoTime()
 | 
|  |    689 |   for (j <- 1 to i) code
 | 
|  |    690 |   val end = System.nanoTime()
 | 
|  |    691 |   ((end - start) / i / 1.0e9) + " secs"
 | 
|  |    692 | }
 | 
|  |    693 | 
 | 
|  |    694 | search(game2).map(pretty)
 | 
| 57 |    695 | search(game3).distinct.length
 | 
| 147 |    696 | time_needed(1, search(game2))
 | 
|  |    697 | time_needed(1, search(game3))
 | 
| 55 |    698 | 
 | 
| 53 |    699 | 
 | 
|  |    700 | 
 | 
|  |    701 | 
 | 
| 150 |    702 | //===================
 | 
|  |    703 | // the end for today
 |