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   |