|      1 // Scala Lecture 2 |      1 // Scala Lecture 2 | 
|      2 //================= |      2 //================= | 
|      3  |      3  | 
|      4  |      4  | 
|      5 // the pain with overloaded math operations |         | 
|      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  |         | 
|     42 for (e <- lst; if (e % 2) == 0; if (e != 4)) yield square(e) |         | 
|     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), |         | 
|     58 // for has no "yield" |         | 
|     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  |         | 
|     74 val test =  |         | 
|     75  for (e <- Set(1, 2, 3, 4, 5, 6, 7, 8, 9); if e < 5) yield square(e) |         | 
|     76  |         | 
|     77  |         | 
|     78  |         | 
|     79 // Option type |      5 // Option type | 
|     80 //============= |      6 //============= | 
|     81  |      7  | 
|     82 //in Java, if something unusually happens, you return null; |      8 //in Java if something unusually happens, you return null; | 
|     83 //in Scala you use Option |      9 //in Scala you use Option | 
|     84 //   - if the value is present, you use Some(value) |     10 //   - if the value is present, you use Some(value) | 
|     85 //   - if no value is present, you use None |     11 //   - if no value is present, you use None | 
|     86  |     12  | 
|     87  |     13  | 
|     88 List(7,24,3,4,5,6).find(_ < 4) |     14 List(7,2,3,4,5,6).find(_ < 4) | 
|     89 List(5,6,7,8,9).find(_ < 4) |     15 List(5,6,7,8,9).find(_ < 4) | 
|     90  |     16  | 
|     91 List(7,2,3,4,5,6).filter(_ < 4) |     17  | 
|     92  |     18 // Values in types | 
|     93 // some operations on Option's |     19 // | 
|         |     20 // Boolean:  | 
|         |     21 // Int:  | 
|         |     22 // String:  | 
|         |     23 // | 
|         |     24 // Option[String]: | 
|         |     25 //    | 
|         |     26  | 
|     94  |     27  | 
|     95 val lst = List(None, Some(1), Some(2), None, Some(3)) |     28 val lst = List(None, Some(1), Some(2), None, Some(3)) | 
|     96  |     29  | 
|     97 lst.flatten |     30 lst.flatten | 
|     98  |     31  | 
|     99 Some(10).get |     32 Some(1).get | 
|    100 None.get |         | 
|    101  |     33  | 
|    102 Some(1).isDefined |     34 Some(1).isDefined | 
|    103 None.isDefined |     35 None.isDefined | 
|    104  |     36  | 
|    105 val ps = List((3, 0), (3, 2), (4, 2), (2, 0), (1, 0), (1, 1)) |     37 val ps = List((3, 0), (3, 2), (4, 2), (2, 0), (1, 0), (1, 1)) | 
|    106  |     38  | 
|    107 for ((x, y) <- ps) yield { |     39 for ((x, y) <- ps) yield { | 
|    108   if (y == 0) None else Some(x / y) |     40   if (y == 0) None else Some(x / y) | 
|    109 } |     41 } | 
|    110  |     42  | 
|    111 // use .getOrElse is for setting a default value |     43 // getOrElse is for setting a default value | 
|    112  |     44  | 
|    113 val lst = List(None, Some(1), Some(2), None, Some(3)) |     45 val lst = List(None, Some(1), Some(2), None, Some(3)) | 
|    114  |         | 
|    115 for (x <- lst) yield x.getOrElse(0) |     46 for (x <- lst) yield x.getOrElse(0) | 
|    116  |     47  | 
|    117  |     48  | 
|    118  |     49  | 
|    119  |     50  | 
|    120 // error handling with Options (no exceptions) |     51 // error handling with Option (no exceptions) | 
|    121 // |         | 
|    122 //  Try(....) |         | 
|    123 // |     52 // | 
|    124 //  Try(something).getOrElse(what_to_do_in_an_exception) |     53 //  Try(something).getOrElse(what_to_do_in_an_exception) | 
|    125 // |     54 // | 
|    126 import scala.util._ |     55 import scala.util._ | 
|    127  |         | 
|    128 Try(1 + 3) |         | 
|    129 Try(9 / 0)  |         | 
|    130  |         | 
|    131 Try(9 / 3).getOrElse(42)  |         | 
|    132 Try(9 / 0).getOrElse(42)  |         | 
|    133  |         | 
|    134  |         | 
|    135 import io.Source |     56 import io.Source | 
|    136  |     57  | 
|    137 val my_url = """https://nms.kcl.ac.uk/christian.urban""" |     58 Source.fromURL("""http://www.inf.kcl.ac.uk/staff/urbanc/""").mkString | 
|    138 //val my_url = """https://nms.kcl.ac.uk/christan.urban"""  // misspelled |     59  | 
|    139  |     60 Try(Source.fromURL("""http://www.inf.kcl.ac.uk/staff/urbanc/""").mkString).getOrElse("") | 
|    140 Source.fromURL(my_url).mkString |     61  | 
|    141  |     62 Try(Some(Source.fromURL("""http://www.inf.kcl.ac.uk/staff/urbanc/""").mkString)).getOrElse(None) | 
|    142 Try(Source.fromURL(my_url).mkString).getOrElse("") |         | 
|    143  |         | 
|    144 Try(Some(Source.fromURL(my_url).mkString)).getOrElse(None) |         | 
|    145  |         | 
|    146  |     63  | 
|    147 // a function that turns strings into numbers |     64 // a function that turns strings into numbers | 
|    148 Integer.parseInt("1234") |     65 Integer.parseInt("12u34") | 
|    149  |         | 
|    150  |     66  | 
|    151 def get_me_an_int(s: String): Option[Int] =  |     67 def get_me_an_int(s: String): Option[Int] =  | 
|    152  Try(Some(Integer.parseInt(s))).getOrElse(None) |     68  Try(Some(Integer.parseInt(s))).getOrElse(None) | 
|    153  |     69  | 
|    154 val lst = List("12345", "foo", "5432", "bar", "x21") |     70 val lst = List("12345", "foo", "5432", "bar", "x21") | 
|    155  |         | 
|    156 for (x <- lst) yield get_me_an_int(x) |     71 for (x <- lst) yield get_me_an_int(x) | 
|    157  |     72  | 
|    158 // summing all the numbers |     73 // summing all the numbers | 
|    159 val sum = (for (i <- lst) yield get_me_an_int(i)).flatten.sum |     74 val sum = lst.flatMap(get_me_an_int(_)).sum | 
|    160  |     75  | 
|    161  |     76  | 
|    162 // This may not look any better than working with null in Java, but to |     77 // 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 |     78 // 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 |     79 // consumer of the get_me_an_int function, and imagine you didn't | 
|    165 // write that function. |     80 // write that function. | 
|    166 // |     81 // | 
|    167 // In Java, if you didn't write this function, you'd have to depend on |     82 // In Java, if you didn't write this function, you'd have to depend on | 
|    168 // the Javadoc of get_me_an_int. If you didn't look at the Javadoc,  |     83 // the Javadoc of the get_me_an_int. If you didn't look at the Javadoc,  | 
|    169 // you might not know that get_me_an_int could return a null, and your  |     84 // you might not know that get_me_an_int could return a null, and your  | 
|    170 // code could potentially throw a NullPointerException. |     85 // code could potentially throw a NullPointerException. | 
|    171  |     86  | 
|    172  |     87  | 
|         |     88  | 
|    173 // even Scala is not immune to problems like this: |     89 // even Scala is not immune to problems like this: | 
|    174  |     90  | 
|    175 List(5,6,7,8,9).indexOf(42) |     91 List(5,6,7,8,9).indexOf(7) | 
|    176  |     92  | 
|    177  |     93  | 
|    178 // ... how are we supposed to know that this returns -1 |     94  | 
|    179  |     95  | 
|    180  |     96  | 
|    181 //other example for options...NaN |     97 // Type abbreviations | 
|    182 val squareRoot: PartialFunction[Double, Double] = {  |     98 //==================== | 
|    183     case d: Double if d > 0 => Math.sqrt(d)  |     99  | 
|    184 } |    100 // some syntactic convenience | 
|    185  |    101 type Pos = (int, Int) | 
|    186 val list: List[Double] = List(4, 16, 25, -9) |    102  | 
|    187  |    103 type Board = List[List[Int]] | 
|    188 val result = list.map(Math.sqrt) |    104  | 
|    189 // => result: List[Double] = List(2.0, 4.0, 5.0, NaN) |    105  | 
|    190  |    106  | 
|    191 val result = list.collect(squareRoot) |    107 // Implicits | 
|    192 // => result: List[Double] = List(2.0, 4.0, 5.0) |    108 //=========== | 
|         |    109 // | 
|         |    110 // for example adding your own methods to Strings: | 
|         |    111 // imagine you want to increment strings, like | 
|         |    112 // | 
|         |    113 //     "HAL".increment | 
|         |    114 // | 
|         |    115 // you can avoid ugly fudges, like a MyString, by | 
|         |    116 // using implicit conversions | 
|         |    117  | 
|         |    118  | 
|         |    119 implicit class MyString(s: String) { | 
|         |    120   def increment = for (c <- s) yield (c + 1).toChar  | 
|         |    121 } | 
|         |    122  | 
|         |    123 "HAL".increment | 
|         |    124  | 
|         |    125  | 
|         |    126 // No return in Scala | 
|         |    127 //==================== | 
|         |    128  | 
|         |    129 //You should not use "return" in Scala: | 
|         |    130 // | 
|         |    131 // A return expression, when evaluated, abandons the  | 
|         |    132 // current computation and returns to the caller of the  | 
|         |    133 // function in which return appears." | 
|         |    134  | 
|         |    135 def sq1(x: Int): Int = x * x | 
|         |    136 def sq2(x: Int): Int = return x * x | 
|         |    137  | 
|         |    138 def sumq(ls: List[Int]): Int = { | 
|         |    139   (for (x <- ls) yield (return x * x)).sum[Int] | 
|         |    140 } | 
|         |    141  | 
|         |    142 sumq(List(1,2,3,4)) | 
|         |    143  | 
|         |    144  | 
|         |    145 // last expression in a function is the return statement | 
|         |    146 def square(x: Int): Int = { | 
|         |    147   println(s"The argument is ${x}.") | 
|         |    148   x * x | 
|         |    149 } | 
|         |    150  | 
|         |    151  | 
|         |    152  | 
|         |    153 // Pattern Matching | 
|         |    154 //================== | 
|         |    155  | 
|         |    156 // A powerful tool which is supposed to come to Java in a few years | 
|         |    157 // time (https://www.youtube.com/watch?v=oGll155-vuQ)...Scala already | 
|         |    158 // has it for many years ;o) | 
|         |    159  | 
|         |    160 // The general schema: | 
|         |    161 // | 
|         |    162 //    expression match { | 
|         |    163 //       case pattern1 => expression1 | 
|         |    164 //       case pattern2 => expression2 | 
|         |    165 //       ... | 
|         |    166 //       case patternN => expressionN | 
|         |    167 //    } | 
|         |    168  | 
|         |    169  | 
|         |    170  | 
|         |    171  | 
|         |    172 // remember | 
|         |    173 val lst = List(None, Some(1), Some(2), None, Some(3)).flatten | 
|         |    174  | 
|         |    175  | 
|         |    176 def my_flatten(xs: List[Option[Int]]): List[Int] = { | 
|         |    177   ... | 
|         |    178 } | 
|         |    179  | 
|         |    180  | 
|         |    181 def my_flatten(lst: List[Option[Int]]): List[Int] = lst match { | 
|         |    182   case Nil => Nil | 
|         |    183   case None::xs => my_flatten(xs) | 
|         |    184   case Some(n)::xs => n::my_flatten(xs) | 
|         |    185 } | 
|         |    186  | 
|         |    187  | 
|         |    188 // another example | 
|         |    189 def get_me_a_string(n: Int): String = n match { | 
|         |    190   case 0 => "zero" | 
|         |    191   case 1 => "one" | 
|         |    192   case 2 => "two" | 
|         |    193   case _ => "many" | 
|         |    194 } | 
|         |    195  | 
|         |    196 get_me_a_string(0) | 
|         |    197  | 
|         |    198 // you can also have cases combined | 
|         |    199 def season(month: String) = month match { | 
|         |    200   case "March" | "April" | "May" => "It's spring" | 
|         |    201   case "June" | "July" | "August" => "It's summer" | 
|         |    202   case "September" | "October" | "November" => "It's autumn" | 
|         |    203   case "December" | "January" | "February" => "It's winter" | 
|         |    204 } | 
|         |    205   | 
|         |    206 println(season("November")) | 
|         |    207  | 
|         |    208 // What happens if no case matches? | 
|         |    209  | 
|         |    210 println(season("foobar")) | 
|         |    211  | 
|         |    212 // fizz buzz | 
|         |    213 def fizz_buzz(n: Int) : String = (n % 3, n % 5) match { | 
|         |    214   case (0, 0) => "fizz buzz" | 
|         |    215   case (0, _) => "fizz" | 
|         |    216   case (_, 0) => "buzz" | 
|         |    217   case _ => n.toString   | 
|         |    218 } | 
|         |    219  | 
|         |    220 for (n <- 0 to 20)  | 
|         |    221  println(fizz_buzz(n)) | 
|         |    222  | 
|         |    223  | 
|         |    224 // User-defined Datatypes | 
|         |    225 //======================== | 
|         |    226  | 
|         |    227 abstract class Tree | 
|         |    228 case class Node(elem: Int, left: Tree, right: Tree) extends Tree | 
|         |    229 case class Leaf() extends Tree | 
|         |    230  | 
|         |    231  | 
|         |    232 def insert(tr: Tree, n: Int): Tree = tr match { | 
|         |    233   case Leaf() => Node(n, Leaf(), Leaf()) | 
|         |    234   case Node(m, left, right) =>  | 
|         |    235     if (n == m) Node(m, left, right)  | 
|         |    236     else if (n < m) Node(m, insert(left, n), right) | 
|         |    237     else Node(m, left, insert(right, n)) | 
|         |    238 } | 
|         |    239  | 
|         |    240  | 
|         |    241 val t1 = Node(4, Node(2, Leaf(), Leaf()), Node(7, Leaf(), Leaf())) | 
|         |    242 insert(t1, 3) | 
|         |    243  | 
|         |    244 def depth(tr: Tree): Int = tr match { | 
|         |    245   case Leaf() => 0 | 
|         |    246   case Node(_, left, right) => 1 + List(depth(left), depth(right)).max | 
|         |    247 } | 
|         |    248  | 
|         |    249  | 
|         |    250 def balance(tr: Tree): Int = tr match { | 
|         |    251   case Leaf() => 0 | 
|         |    252   case Node(_, left, right) => depth(left) - depth(right) | 
|         |    253 } | 
|         |    254  | 
|         |    255 balance(insert(t1, 3)) | 
|         |    256  | 
|         |    257 // another example | 
|         |    258  | 
|         |    259 abstract class Person | 
|         |    260 case class King() extends Person | 
|         |    261 case class Peer(deg: String, terr: String, succ: Int) extends Person | 
|         |    262 case class Knight(name: String) extends Person | 
|         |    263 case class Peasant(name: String) extends Person | 
|         |    264 case class Clown() extends Person | 
|         |    265  | 
|         |    266 def title(p: Person): String = p match { | 
|         |    267   case King() => "His Majesty the King" | 
|         |    268   case Peer(deg, terr, _) => s"The ${deg} of ${terr}" | 
|         |    269   case Knight(name) => s"Sir ${name}" | 
|         |    270   case Peasant(name) => name | 
|         |    271 } | 
|         |    272  | 
|         |    273 def superior(p1: Person, p2: Person): Boolean = (p1, p2) match { | 
|         |    274   case (King(), _) => true | 
|         |    275   case (Peer(_,_,_), Knight(_)) => true | 
|         |    276   case (Peer(_,_,_), Peasant(_)) => true | 
|         |    277   case (Peer(_,_,_), Clown()) => true | 
|         |    278   case (Knight(_), Peasant(_)) => true | 
|         |    279   case (Knight(_), Clown()) => true | 
|         |    280   case (Clown(), Peasant(_)) => true | 
|         |    281   case _ => false | 
|         |    282 } | 
|         |    283  | 
|         |    284 val people = List(Knight("David"),  | 
|         |    285                   Peer("Duke", "Norfolk", 84),  | 
|         |    286                   Peasant("Christian"),  | 
|         |    287                   King(),  | 
|         |    288                   Clown()) | 
|         |    289  | 
|         |    290 println(people.sortWith(superior(_, _)).mkString(", ")) | 
|         |    291  | 
|    193  |    292  | 
|    194  |    293  | 
|    195 // Higher-Order Functions |    294 // Higher-Order Functions | 
|    196 //======================== |    295 //======================== | 
|    197  |    296  | 
|    198 // functions can take functions as arguments |    297 // functions can take functions as arguments | 
|    199  |    298  | 
|    200 val lst = (1 to 10).toList |    299 val lst = (1 to 10).toList | 
|    201  |    300  | 
|    202 def even(x: Int) : Boolean = x % 2 == 0 |    301 def even(x: Int): Boolean = x % 2 == 0 | 
|    203 def odd(x: Int) : Boolean = x % 2 == 1 |    302 def odd(x: Int): Boolean = x % 2 == 1 | 
|    204  |    303  | 
|    205 lst.filter(x => even(x) && odd(x)) |    304 lst.filter(x => even(x)) | 
|    206 lst.filter(even(_)) |    305 lst.filter(even(_)) | 
|    207 lst.filter(odd && even) |    306 lst.filter(even) | 
|    208  |    307  | 
|    209 lst.find(_ > 8) |    308 lst.find(_ > 8) | 
|    210  |    309  | 
|    211 // map applies a function to each element of a list |         | 
|    212  |         | 
|    213 def square(x: Int): Int = x * x |    310 def square(x: Int): Int = x * x | 
|    214  |    311  | 
|    215 val lst = (1 to 10).toList |         | 
|    216 lst.map(square) |    312 lst.map(square) | 
|    217  |    313  | 
|    218 lst.map(square).filter(_ > 4) |    314 lst.map(square).filter(_ > 4) | 
|    219  |    315  | 
|    220 lst.map(square).filter(_ > 4).map(square) |    316 lst.map(square).filter(_ > 4).map(square) | 
|    221  |    317  | 
|    222 // map works for most collection types, including sets |    318 // in my collatz.scala | 
|    223 Set(1, 3, 6).map(square).filter(_ > 4) |    319 //(1 to bnd).map(i => (collatz(i), i)).maxBy(_._1) | 
|    224  |    320  | 
|    225  |    321  | 
|    226 val l = List((1, 3),(2, 4),(4, 1),(6, 2)) |    322 // type of functions, for example f: Int => Int | 
|    227  |    323  | 
|    228 l.map(square(_._1)) |    324 def my_map_int(lst: List[Int], f: Int => Int): List[Int] = lst match { | 
|    229  |    325   case Nil => Nil | 
|    230  |    326   case x::xs => f(x)::my_map_int(xs, f) | 
|    231 // Why are functions as arguments useful? |    327 } | 
|    232 // |    328  | 
|    233 // Consider the sum between a and b: |    329 my_map_int(lst, square) | 
|    234  |         | 
|    235 def sumInts(a: Int, b: Int) : Int =  |         | 
|    236   if (a > b) 0 else a + sumInts(a + 1, b) |         | 
|    237  |         | 
|    238  |         | 
|    239 sumInts(10, 16) |         | 
|    240  |         | 
|    241 // sum squares |         | 
|    242 def square(n: Int) : Int = n * n |         | 
|    243  |         | 
|    244 def sumSquares(a: Int, b: Int) : Int =  |         | 
|    245   if (a > b) 0 else square(a) + sumSquares(a + 1, b) |         | 
|    246  |         | 
|    247 sumSquares(2, 6) |         | 
|    248  |         | 
|    249  |         | 
|    250 // sum factorials |         | 
|    251 def fact(n: Int) : Int =   |         | 
|    252   if (n == 0) 1 else n * fact(n - 1) |         | 
|    253  |         | 
|    254 def sumFacts(a: Int, b: Int) : Int =  |         | 
|    255   if (a > b) 0 else fact(a) + sumFacts(a + 1, b) |         | 
|    256  |         | 
|    257 sumFacts(2, 6) |         | 
|    258  |         | 
|    259  |         | 
|    260  |         | 
|    261 // You can see the pattern....can we simplify our work? |         | 
|    262 // The type of functions from ints to ints: Int => Int |         | 
|    263  |         | 
|    264 def sum(f: Int => Int, a: Int, b: Int) : Int = { |         | 
|    265   if (a > b) 0  |         | 
|    266   else f(a) + sum(f, a + 1, b) |         | 
|    267 } |         | 
|    268  |         | 
|    269  |         | 
|    270 def sumSquares(a: Int, b: Int) : Int = sum(square, a, b) |         | 
|    271 def sumFacts(a: Int, b: Int) : Int = sum(fact, a, b) |         | 
|    272  |         | 
|    273 // What should we do for sumInts? |         | 
|    274  |         | 
|    275 def id(n: Int) : Int = n |         | 
|    276 def sumInts(a: Int, b: Int) : Int = sum(id, a, b) |         | 
|    277  |         | 
|    278 sumInts(10, 12) |         | 
|    279  |         | 
|    280  |         | 
|    281 // Anonymous Functions: You can also write: |         | 
|    282  |         | 
|    283 def sumCubes(a: Int, b: Int) : Int =   sum(x => x * x * x, a, b) |         | 
|    284 def sumSquares(a: Int, b: Int) : Int = sum(x => x * x, a, b) |         | 
|    285 def sumInts(a: Int, b: Int) : Int    = sum(x => x, a, b) |         | 
|    286  |         | 
|    287  |    330  | 
|    288 // other function types |    331 // other function types | 
|    289 // |    332 // | 
|    290 // f1: (Int, Int) => Int |    333 // f1: (Int, Int) => Int | 
|    291 // f2: List[String] => Option[Int] |    334 // f2: List[String] => Option[Int] | 
|    292 // ...  |    335 // ...  | 
|    293  |    336  | 
|    294  |    337  | 
|    295 // an aside: partial application |    338 def sumOf(f: Int => Int, lst: List[Int]): Int = lst match { | 
|    296  |    339   case Nil => 0 | 
|    297 def add(a: Int)(b: Int) : Int = a + b |    340   case x::xs => f(x) + sumOf(f, xs) | 
|    298 def add_abc(a: Int)(b: Int)(c: Int) : Int = a + b + c |    341 } | 
|    299  |    342  | 
|    300 val add2 : Int => Int = add(2) |    343 def sum_squares(lst: List[Int]) = sumOf(square, lst) | 
|    301 add2(5) |    344 def sum_cubes(lst: List[Int])   = sumOf(x => x * x * x, lst) | 
|    302  |    345  | 
|    303 val add2_bc : Int => Int => Int = add_abc(2)  |    346 sum_squares(lst) | 
|    304 val add2_9_c : Int => Int = add2_bc(9)  |    347 sum_cubes(lst) | 
|    305  |    348  | 
|    306 add2_9_c(10) |    349 // lets try it factorial | 
|    307  |    350 def fact(n: Int): Int = ... | 
|    308 sum(add(2), 0, 2) |    351  | 
|    309 sum(add(10), 0, 2) |    352 def sum_fact(lst: List[Int]) = sumOf(fact, lst) | 
|    310  |    353 sum_fact(lst) | 
|    311  |    354  | 
|    312  |    355 // Avoid being mutable | 
|    313  |    356 //===================== | 
|    314 // some automatic timing in each evaluation |    357  | 
|    315 package wrappers {   |    358 // a student showed me... | 
|    316  |    359 import scala.collection.mutable.ListBuffer | 
|    317   object wrap {  |    360  | 
|    318     |    361  | 
|    319     def timed[R](block: => R): R = { |    362  | 
|    320       val t0 = System.nanoTime() |    363 def collatz_max(bnd: Long): (Long, Long) = { | 
|    321       val result = block |    364   val colNos = ListBuffer[(Long, Long)]() | 
|    322       println("Elapsed time: " + (System.nanoTime - t0) + "ns") |    365   for (i <- (1L to bnd).toList) colNos += ((collatz(i), i)) | 
|    323       result |    366   colNos.max | 
|    324     } |    367 } | 
|    325  |    368  | 
|    326     def apply[A](a: => A): A = {  |    369 def collatz_max(bnd: Long): (Long, Long) = { | 
|    327       timed(a) |    370   (1L to bnd).map((i) => (collatz(i), i)).maxBy(_._1) | 
|    328     }  |    371 } | 
|    329   } |    372  | 
|    330 } |    373 //views -> lazy collection | 
|    331  |    374 def collatz_max(bnd: Long): (Long, Long) = { | 
|    332 $intp.setExecutionWrapper("wrappers.wrap") |    375   (1L to bnd).view.map((i) => (collatz(i), i)).maxBy(_._1) | 
|    333  |    376 } | 
|    334 // Iteration |    377  | 
|    335  |    378 // raises a GC exception | 
|    336 def fib(n: Int) : Int =  |    379 (1 to 1000000000).filter(_ % 2 == 0).take(10).toList | 
|    337   if (n <= 1) 1 else fib(n - 1) + fib(n - 2) |    380 // ==> java.lang.OutOfMemoryError: GC overhead limit exceeded | 
|    338  |    381  | 
|    339 fib(10) |    382 (1 to 1000000000).view.filter(_ % 2 == 0).take(10).toList | 
|    340  |    383  | 
|    341  |    384  | 
|    342 Iterator.iterate((1,1)){ case (n: Int, m: Int) => (n + m, n) }.drop(9).next |    385  | 
|    343  |    386 // Sudoku | 
|    344  |    387 //======== | 
|    345  |         | 
|    346  |         | 
|    347 // Function Composition |         | 
|    348 //====================== |         | 
|    349  |         | 
|    350 // How can be Higher-Order Functions and Options be helpful? |         | 
|    351  |         | 
|    352 def add_footer(msg: String) : String = msg ++ " - Sent from iOS" |         | 
|    353  |         | 
|    354 def valid_msg(msg: String) : Boolean = msg.size <= 140 |         | 
|    355  |         | 
|    356 def duplicate(s: String) : String = s ++ s |         | 
|    357  |         | 
|    358 // they compose very nicely, e.g |         | 
|    359  |         | 
|    360 valid_msg(add_footer("Hello World")) |         | 
|    361 valid_msg(duplicate(duplicate(add_footer("Helloooooooooooooooooo World")))) |         | 
|    362  |         | 
|    363 // but not all functions do |         | 
|    364 // first_word: let's first do it the ugly Java way using null: |         | 
|    365  |         | 
|    366 def first_word(msg: String) : String = { |         | 
|    367   val words = msg.split(" ") |         | 
|    368   if (words(0) != "") words(0) else null |         | 
|    369 } |         | 
|    370  |         | 
|    371 duplicate(first_word("Hello World")) |         | 
|    372 duplicate(first_word("")) |         | 
|    373  |         | 
|    374 def extended_duplicate(s: String) : String =  |         | 
|    375   if (s != null) s ++ s else null |         | 
|    376  |         | 
|    377 extended_duplicate(first_word("")) |         | 
|    378  |         | 
|    379 // but this is against the rules of the game: we do not want |         | 
|    380 // to change duplicate, because first_word might return null |         | 
|    381  |         | 
|    382  |         | 
|    383 // Avoid always null! |         | 
|    384 def better_first_word(msg: String) : Option[String] = { |         | 
|    385   val words = msg.split(" ") |         | 
|    386   if (words(0) != "") Some(words(0)) else None |         | 
|    387 } |         | 
|    388  |         | 
|    389 better_first_word("Hello World").map(duplicate) |         | 
|    390  |         | 
|    391 better_first_word("Hello World").map(duplicate) |         | 
|    392 better_first_word("").map(duplicate).map(duplicate).map(valid_msg) |         | 
|    393  |         | 
|    394 better_first_word("").map(duplicate) |         | 
|    395 better_first_word("").map(duplicate).map(valid_msg) |         | 
|    396  |         | 
|    397  |         | 
|    398  |         | 
|    399  |         | 
|    400  |         | 
|    401 // Problems with mutability and parallel computations |         | 
|    402 //==================================================== |         | 
|    403  |         | 
|    404 def count_intersection(A: Set[Int], B: Set[Int]) : Int = { |         | 
|    405   var count = 0 |         | 
|    406   for (x <- A; if (B contains x)) count += 1  |         | 
|    407   count |         | 
|    408 } |         | 
|    409  |         | 
|    410 val A = (1 to 1000).toSet |         | 
|    411 val B = (1 to 1000 by 4).toSet |         | 
|    412  |         | 
|    413 count_intersection(A, B) |         | 
|    414  |         | 
|    415 // but do not try to add .par to the for-loop above, |         | 
|    416 // otherwise you will be caught in race-condition hell. |         | 
|    417  |         | 
|    418  |         | 
|    419 //propper parallel version |         | 
|    420 def count_intersection2(A: Set[Int], B: Set[Int]) : Int =  |         | 
|    421   A.par.count(x => B contains x) |         | 
|    422  |         | 
|    423 count_intersection2(A, B) |         | 
|    424  |         | 
|    425  |         | 
|    426 //for measuring time |         | 
|    427 def time_needed[T](n: Int, code: => T) = { |         | 
|    428   val start = System.nanoTime() |         | 
|    429   for (i <- (0 to n)) code |         | 
|    430   val end = System.nanoTime() |         | 
|    431   (end - start) / 1.0e9 |         | 
|    432 } |         | 
|    433  |         | 
|    434 val A = (1 to 1000000).toSet |         | 
|    435 val B = (1 to 1000000 by 4).toSet |         | 
|    436  |         | 
|    437 time_needed(10, count_intersection(A, B)) |         | 
|    438 time_needed(10, count_intersection2(A, B)) |         | 
|    439  |         | 
|    440  |         | 
|    441  |         | 
|    442  |         | 
|    443  |         | 
|    444  |         | 
|    445 // No returns in Scala |         | 
|    446 //==================== |         | 
|    447  |         | 
|    448 // You should not use "return" in Scala: |         | 
|    449 // |         | 
|    450 // A return expression, when evaluated, abandons the  |         | 
|    451 // current computation and returns to the caller of the  |         | 
|    452 // function in which return appears." |         | 
|    453  |         | 
|    454 def sq1(x: Int): Int = x * x |         | 
|    455 def sumq(ls: List[Int]): Int =  |         | 
|    456   ls.map(x => x * x).sum |         | 
|    457  |         | 
|    458  |         | 
|    459  |         | 
|    460  |         | 
|    461 def sq2(x: Int): Int = return x * x |         | 
|    462  |         | 
|    463 def sumq(ls: List[Int]): Int = { |         | 
|    464   ls.map(sq1).sum[Int] |         | 
|    465 } |         | 
|    466  |         | 
|    467 sumq(List(1, 2, 3, 4)) |         | 
|    468  |         | 
|    469  |         | 
|    470  |         | 
|    471 def sumq(ls: List[Int]): Int = { |         | 
|    472   val sqs : List[Int] = for (x <- ls) yield (return x * x) |         | 
|    473   sqs.sum |         | 
|    474 } |         | 
|    475  |         | 
|    476 sumq(List(1, 2, 3, 4)) |         | 
|    477  |         | 
|    478  |         | 
|    479  |         | 
|    480 // Type abbreviations |         | 
|    481 //==================== |         | 
|    482  |         | 
|    483 // some syntactic convenience |         | 
|    484  |         | 
|    485 type Pos = (int, Int) |         | 
|    486 type Board = List[List[Int]] |         | 
|    487  |         | 
|    488  |         | 
|    489  |         | 
|    490  |         | 
|    491 // Sudoku in Scala |         | 
|    492 //================= |         | 
|    493  |    388  | 
|    494 // THE POINT OF THIS CODE IS NOT TO BE SUPER |    389 // THE POINT OF THIS CODE IS NOT TO BE SUPER | 
|    495 // EFFICIENT AND FAST, just explaining exhaustive |    390 // EFFICIENT AND FAST, just explaining exhaustive | 
|    496 // depth-first search |    391 // depth-first search | 
|    497  |    392  |