1 // Scala Lecture 2  | 
     1 // Scala Lecture 2  | 
     2 //=================  | 
     2 //=================  | 
     3   | 
     3   | 
     4   | 
     4   | 
         | 
     5 // 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) 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 // 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 for (e <- Set(1, 2, 3, 4, 5, 6, 7, 8, 9); if e < 5) yield square(e)  | 
         | 
    75   | 
         | 
    76   | 
     5 // Option type  | 
    77 // Option type  | 
     6 //=============  | 
    78 //=============  | 
     7   | 
    79   | 
     8 //in Java if something unusually happens, you return null;  | 
    80 //in Java, if something unusually happens, you return null;  | 
     9 //in Scala you use Option  | 
    81 //in Scala you use Option  | 
    10 //   - if the value is present, you use Some(value)  | 
    82 //   - if the value is present, you use Some(value)  | 
    11 //   - if no value is present, you use None  | 
    83 //   - if no value is present, you use None  | 
    12   | 
    84   | 
    13   | 
    85   | 
    14 List(7,2,3,4,5,6).find(_ < 4)  | 
    86 List(7,2,3,4,5,6).find(_ < 4)  | 
    15 List(5,6,7,8,9).find(_ < 4)  | 
    87 List(5,6,7,8,9).find(_ < 4)  | 
    16   | 
    88   | 
    17   | 
    89   | 
    18 // Values in types  | 
    90 // some operations on Option's  | 
    19 //  | 
         | 
    20 // Boolean:   | 
         | 
    21 // Int:   | 
         | 
    22 // String:   | 
         | 
    23 //  | 
         | 
    24 // Option[String]:  | 
         | 
    25 //     | 
         | 
    26   | 
         | 
    27   | 
    91   | 
    28 val lst = List(None, Some(1), Some(2), None, Some(3))  | 
    92 val lst = List(None, Some(1), Some(2), None, Some(3))  | 
    29   | 
    93   | 
    30 lst.flatten  | 
    94 lst.flatten  | 
    31   | 
    95   | 
    38   | 
   102   | 
    39 for ((x, y) <- ps) yield { | 
   103 for ((x, y) <- ps) yield { | 
    40   if (y == 0) None else Some(x / y)  | 
   104   if (y == 0) None else Some(x / y)  | 
    41 }  | 
   105 }  | 
    42   | 
   106   | 
    43 // getOrElse is for setting a default value  | 
   107 // use .getOrElse is for setting a default value  | 
    44   | 
   108   | 
    45 val lst = List(None, Some(1), Some(2), None, Some(3))  | 
   109 val lst = List(None, Some(1), Some(2), None, Some(3))  | 
         | 
   110   | 
    46 for (x <- lst) yield x.getOrElse(0)  | 
   111 for (x <- lst) yield x.getOrElse(0)  | 
    47   | 
   112   | 
    48   | 
   113   | 
    49   | 
   114   | 
    50   | 
   115   | 
    51 // error handling with Option (no exceptions)  | 
   116 // error handling with Options (no exceptions)  | 
         | 
   117 //  | 
         | 
   118 //  Try(....)  | 
    52 //  | 
   119 //  | 
    53 //  Try(something).getOrElse(what_to_do_in_an_exception)  | 
   120 //  Try(something).getOrElse(what_to_do_in_an_exception)  | 
    54 //  | 
   121 //  | 
    55 import scala.util._  | 
   122 import scala.util._  | 
         | 
   123   | 
         | 
   124 Try(1 + 3)  | 
         | 
   125 Try(9 / 0)   | 
         | 
   126   | 
         | 
   127 Try(9 / 3).getOrElse(42)   | 
         | 
   128 Try(9 / 0).getOrElse(42)   | 
         | 
   129   | 
         | 
   130   | 
    56 import io.Source  | 
   131 import io.Source  | 
    57   | 
   132   | 
    58 Source.fromURL("""http://www.inf.kcl.ac.uk/staff/urbanc/""").mkString | 
   133 val my_url = """https://nms.kcl.ac.uk/christian.urban"""  | 
    59   | 
   134   | 
    60 Try(Source.fromURL("""http://www.inf.kcl.ac.uk/staff/urbanc/""").mkString).getOrElse("") | 
   135 Source.fromURL(my_url).mkString  | 
    61   | 
   136   | 
    62 Try(Some(Source.fromURL("""http://www.inf.kcl.ac.uk/staff/urbanc/""").mkString)).getOrElse(None) | 
   137 Try(Source.fromURL(my_url).mkString).getOrElse("") | 
         | 
   138   | 
         | 
   139 Try(Some(Source.fromURL(my_url).mkString)).getOrElse(None)  | 
         | 
   140   | 
    63   | 
   141   | 
    64 // a function that turns strings into numbers  | 
   142 // a function that turns strings into numbers  | 
    65 Integer.parseInt("12u34") | 
   143 Integer.parseInt("1234") | 
         | 
   144   | 
    66   | 
   145   | 
    67 def get_me_an_int(s: String): Option[Int] =   | 
   146 def get_me_an_int(s: String): Option[Int] =   | 
    68  Try(Some(Integer.parseInt(s))).getOrElse(None)  | 
   147  Try(Some(Integer.parseInt(s))).getOrElse(None)  | 
    69   | 
   148   | 
    70 val lst = List("12345", "foo", "5432", "bar", "x21") | 
   149 val lst = List("12345", "foo", "5432", "bar", "x21") | 
         | 
   150   | 
    71 for (x <- lst) yield get_me_an_int(x)  | 
   151 for (x <- lst) yield get_me_an_int(x)  | 
    72   | 
   152   | 
    73 // summing all the numbers  | 
   153 // summing all the numbers  | 
    74 val sum = lst.flatMap(get_me_an_int(_)).sum  | 
   154 val sum = (for (i <- lst) yield get_me_an_int(i)).flatten.sum  | 
    75   | 
   155   | 
    76   | 
   156   | 
    77 // This may not look any better than working with null in Java, but to  | 
   157 // This may not look any better than working with null in Java, but to  | 
    78 // see the value, you have to put yourself in the shoes of the  | 
   158 // see the value, you have to put yourself in the shoes of the  | 
    79 // consumer of the get_me_an_int function, and imagine you didn't  | 
   159 // consumer of the get_me_an_int function, and imagine you didn't  | 
    80 // write that function.  | 
   160 // write that function.  | 
    81 //  | 
   161 //  | 
    82 // In Java, if you didn't write this function, you'd have to depend on  | 
   162 // In Java, if you didn't write this function, you'd have to depend on  | 
    83 // the Javadoc of the get_me_an_int. If you didn't look at the Javadoc,   | 
   163 // the Javadoc of get_me_an_int. If you didn't look at the Javadoc,   | 
    84 // you might not know that get_me_an_int could return a null, and your   | 
   164 // you might not know that get_me_an_int could return a null, and your   | 
    85 // code could potentially throw a NullPointerException.  | 
   165 // code could potentially throw a NullPointerException.  | 
    86   | 
   166   | 
    87   | 
   167   | 
    88   | 
         | 
    89 // even Scala is not immune to problems like this:  | 
   168 // even Scala is not immune to problems like this:  | 
    90   | 
   169   | 
    91 List(5,6,7,8,9).indexOf(7)  | 
   170 List(5,6,7,8,9).indexOf(7)  | 
    92   | 
   171   | 
         | 
   172   | 
         | 
   173   | 
         | 
   174   | 
         | 
   175 // Higher-Order Functions  | 
         | 
   176 //========================  | 
         | 
   177   | 
         | 
   178 // functions can take functions as arguments  | 
         | 
   179   | 
         | 
   180 val lst = (1 to 10).toList  | 
         | 
   181   | 
         | 
   182 def even(x: Int) : Boolean = x % 2 == 0  | 
         | 
   183 def odd(x: Int) : Boolean = x % 2 == 1  | 
         | 
   184   | 
         | 
   185 lst.filter(x => even(x))  | 
         | 
   186 lst.filter(even(_))  | 
         | 
   187 lst.filter(even)  | 
         | 
   188   | 
         | 
   189 lst.find(_ > 8)  | 
         | 
   190   | 
         | 
   191 // map applies a function to each element of a list  | 
         | 
   192   | 
         | 
   193 def square(x: Int): Int = x * x  | 
         | 
   194   | 
         | 
   195 lst.map(square)  | 
         | 
   196   | 
         | 
   197 lst.map(square).filter(_ > 4)  | 
         | 
   198   | 
         | 
   199 lst.map(square).filter(_ > 4).map(square)  | 
         | 
   200   | 
         | 
   201 // map works for most collection types, including sets  | 
         | 
   202 Set(1, 3, 6).map(square)  | 
         | 
   203   | 
         | 
   204   | 
         | 
   205 // Why could functions as arguments be useful?  | 
         | 
   206 //  | 
         | 
   207 // Consider the sum between a and b:  | 
         | 
   208   | 
         | 
   209 def sumInts(a: Int, b: Int) : Int =   | 
         | 
   210   if (a > b) 0 else a + sumInts(a + 1, b)  | 
         | 
   211   | 
         | 
   212   | 
         | 
   213 sumInt(10, 16)  | 
         | 
   214   | 
         | 
   215 // sum squares  | 
         | 
   216 def square(n: Int) : Int = n * n  | 
         | 
   217   | 
         | 
   218 def sumSquares(a: Int, b: Int) : Int =   | 
         | 
   219   if (a > b) 0 else square(a) + sumSquares(a + 1, b)  | 
         | 
   220   | 
         | 
   221 sumSquares(2, 6)  | 
         | 
   222   | 
         | 
   223   | 
         | 
   224 // sum factorials  | 
         | 
   225 def fact(n: Int) : Int =    | 
         | 
   226   if (n == 0) 1 else n * fact(n - 1)  | 
         | 
   227   | 
         | 
   228 def sumFacts(a: Int, b: Int) : Int =   | 
         | 
   229   if (a > b) 0 else fact(a) + sumFacts(a + 1, b)  | 
         | 
   230   | 
         | 
   231 sumFacts(2, 6)  | 
         | 
   232   | 
         | 
   233   | 
         | 
   234   | 
         | 
   235 // You can see the pattern....can we simplify out work?  | 
         | 
   236 // The type of functions from ints to ints: Int => Int  | 
         | 
   237   | 
         | 
   238 def sum(f: Int => Int, a: Int, b: Int) : Int = { | 
         | 
   239   if (a > b) 0   | 
         | 
   240   else f(a) + sum(f, a + 1, b)  | 
         | 
   241 }  | 
         | 
   242   | 
         | 
   243   | 
         | 
   244 def sumSquares(a: Int, b: Int) : Int = sum(square, a, b)  | 
         | 
   245 def sumFacts(a: Int, b: Int) : Int = sum(fact, a, b)  | 
         | 
   246   | 
         | 
   247 // What should we do for sumInts?  | 
         | 
   248   | 
         | 
   249 def id(n: Int) : Int = n  | 
         | 
   250 def sumInts(a: Int, b: Int) : Int = sum(id, a, b)  | 
         | 
   251   | 
         | 
   252   | 
         | 
   253   | 
         | 
   254 // Anonymous Functions: You can also write:  | 
         | 
   255   | 
         | 
   256 def sumCubes(a: Int, b: Int) : Int =   sum(x => x * x * x, a, b)  | 
         | 
   257 def sumSquares(a: Int, b: Int) : Int = sum(x => x * x, a, b)  | 
         | 
   258 def sumInts(a: Int, b: Int) : Int    = sum(x => x, a, b)  | 
         | 
   259   | 
         | 
   260   | 
         | 
   261 // other function types  | 
         | 
   262 //  | 
         | 
   263 // f1: (Int, Int) => Int  | 
         | 
   264 // f2: List[String] => Option[Int]  | 
         | 
   265 // ...   | 
         | 
   266   | 
         | 
   267   | 
         | 
   268 // Function Composition  | 
         | 
   269 //======================  | 
         | 
   270   | 
         | 
   271 // How could Higher-Order Functions and Options be helpful?  | 
         | 
   272   | 
         | 
   273 def add_footer(msg: String) : String = msg ++ " - Sent from iOS"  | 
         | 
   274   | 
         | 
   275 def valid_msg(msg: String) : Boolean = msg.size <= 140  | 
         | 
   276   | 
         | 
   277 def duplicate(s: String) : String = s ++ s  | 
         | 
   278   | 
         | 
   279 // they compose nicely  | 
         | 
   280 valid_msg(add_footer("Hello World")) | 
         | 
   281 valid_msg(duplicate(add_footer("Hello World"))) | 
         | 
   282   | 
         | 
   283   | 
         | 
   284 // first_word: let's first do it the ugly Java way using null:  | 
         | 
   285   | 
         | 
   286 def first_word(msg: String) : String = { | 
         | 
   287   val words = msg.split(" ") | 
         | 
   288   if (words(0) != "") words(0) else null  | 
         | 
   289 }  | 
         | 
   290   | 
         | 
   291 duplicate(first_word("Hello World")) | 
         | 
   292 duplicate(first_word("")) | 
         | 
   293   | 
         | 
   294 def extended_duplicate(s: String) : String =   | 
         | 
   295   if (s != null) s ++ s else null  | 
         | 
   296   | 
         | 
   297 extended_duplicate(first_word("")) | 
         | 
   298   | 
         | 
   299   | 
         | 
   300 // Avoid always null!  | 
         | 
   301 def better_first_word(msg: String) : Option[String] = { | 
         | 
   302   val words = msg.split(" ") | 
         | 
   303   if (words(0) != "") Some(words(0)) else None  | 
         | 
   304 }  | 
         | 
   305   | 
         | 
   306 better_first_word("Hello World").map(duplicate) | 
         | 
   307 better_first_word("Hello World").map(duplicate).map(duplicate).map(valid_msg) | 
         | 
   308   | 
         | 
   309 better_first_word("").map(duplicate) | 
         | 
   310 better_first_word("").map(duplicate).map(valid_msg) | 
    93   | 
   311   | 
    94   | 
   312   | 
    95   | 
   313   | 
    96   | 
   314   | 
    97 // Type abbreviations  | 
   315 // Type abbreviations  | 
    98 //====================  | 
   316 //====================  | 
    99   | 
   317   | 
   100 // some syntactic convenience  | 
   318 // some syntactic convenience  | 
         | 
   319   | 
   101 type Pos = (int, Int)  | 
   320 type Pos = (int, Int)  | 
   102   | 
         | 
   103 type Board = List[List[Int]]  | 
   321 type Board = List[List[Int]]  | 
   104   | 
   322   | 
   105   | 
   323   | 
   106   | 
   324   | 
   107 // Implicits  | 
   325 // Implicits (Cool Feature)  | 
   108 //===========  | 
   326 //=========================  | 
   109 //  | 
   327 //  | 
   110 // for example adding your own methods to Strings:  | 
   328 // For example adding your own methods to Strings:  | 
   111 // imagine you want to increment strings, like  | 
   329 // Imagine you want to increment strings, like  | 
   112 //  | 
   330 //  | 
   113 //     "HAL".increment  | 
   331 //     "HAL".increment  | 
   114 //  | 
   332 //  | 
   115 // you can avoid ugly fudges, like a MyString, by  | 
   333 // you can avoid ugly fudges, like a MyString, by  | 
   116 // using implicit conversions  | 
   334 // using implicit conversions.  | 
   117   | 
   335   | 
   118   | 
   336   | 
   119 implicit class MyString(s: String) { | 
   337 implicit class MyString(s: String) { | 
   120   def increment = for (c <- s) yield (c + 1).toChar   | 
   338   def increment = for (c <- s) yield (c + 1).toChar   | 
   121 }  | 
   339 }  | 
   122   | 
   340   | 
   123 "HAL".increment  | 
   341 "HAL".increment  | 
   124   | 
   342   | 
   125   | 
   343   | 
   126 // No return in Scala  | 
   344   | 
         | 
   345 // No returns in Scala  | 
   127 //====================  | 
   346 //====================  | 
   128   | 
   347   | 
   129 //You should not use "return" in Scala:  | 
   348 // You should not use "return" in Scala:  | 
   130 //  | 
   349 //  | 
   131 // A return expression, when evaluated, abandons the   | 
   350 // A return expression, when evaluated, abandons the   | 
   132 // current computation and returns to the caller of the   | 
   351 // current computation and returns to the caller of the   | 
   133 // function in which return appears."  | 
   352 // function in which return appears."  | 
   134   | 
   353   | 
   135 def sq1(x: Int): Int = x * x  | 
   354 def sq1(x: Int): Int = x * x  | 
   136 def sq2(x: Int): Int = return x * x  | 
   355 def sq2(x: Int): Int = return x * x  | 
   137   | 
   356   | 
   138 def sumq(ls: List[Int]): Int = { | 
   357 def sumq(ls: List[Int]): Int = { | 
   139   (for (x <- ls) yield (return x * x)).sum[Int]  | 
   358   ls.map(sq1).sum[Int]  | 
   140 }  | 
   359 }  | 
   141   | 
   360   | 
   142 sumq(List(1,2,3,4))  | 
   361 sumq(List(1, 2, 3, 4))  | 
   143   | 
   362   | 
   144   | 
   363   | 
   145 // last expression in a function is the return statement  | 
   364   | 
   146 def square(x: Int): Int = { | 
   365 def sumq(ls: List[Int]): Int = { | 
   147   println(s"The argument is ${x}.") | 
   366   val sqs : List[Int] = for (x <- ls) yield (return x * x)  | 
   148   x * x  | 
   367   sqs.sum  | 
   149 }  | 
   368 }  | 
         | 
   369   | 
   150   | 
   370   | 
   151   | 
   371   | 
   152   | 
   372   | 
   153 // Pattern Matching  | 
   373 // Pattern Matching  | 
   154 //==================  | 
   374 //==================  | 
   209   | 
   428   | 
   210 // What happens if no case matches?  | 
   429 // What happens if no case matches?  | 
   211   | 
   430   | 
   212 println(season("foobar")) | 
   431 println(season("foobar")) | 
   213   | 
   432   | 
         | 
   433   | 
   214 // User-defined Datatypes  | 
   434 // User-defined Datatypes  | 
   215 //========================  | 
   435 //========================  | 
   216   | 
   436   | 
   217 abstract class Tree  | 
   437 abstract class Colour  | 
   218 case class Node(elem: Int, left: Tree, right: Tree) extends Tree  | 
   438 case class Red() extends Colour   | 
   219 case class Leaf() extends Tree  | 
   439 case class Green() extends Colour   | 
   220   | 
   440 case class Blue() extends Colour  | 
   221   | 
   441   | 
   222 def insert(tr: Tree, n: Int): Tree = tr match { | 
   442 def fav_colour(c: Colour) : Boolean = c match { | 
   223   case Leaf() => Node(n, Leaf(), Leaf())  | 
   443   case Red()   => false  | 
   224   case Node(m, left, right) =>   | 
   444   case Green() => true  | 
   225     if (n == m) Node(m, left, right)   | 
   445   case Blue()  => false   | 
   226     else if (n < m) Node(m, insert(left, n), right)  | 
   446 }  | 
   227     else Node(m, left, insert(right, n))  | 
   447   | 
   228 }  | 
   448   | 
   229   | 
   449 // actually this can be written with "object"  | 
   230   | 
   450   | 
   231 val t1 = Node(4, Node(2, Leaf(), Leaf()), Node(7, Leaf(), Leaf()))  | 
         | 
   232 insert(t1, 3)  | 
         | 
   233   | 
         | 
   234 def depth(tr: Tree): Int = tr match { | 
         | 
   235   case Leaf() => 0  | 
         | 
   236   case Node(_, left, right) => 1 + List(depth(left), depth(right)).max  | 
         | 
   237 }  | 
         | 
   238   | 
         | 
   239   | 
         | 
   240 def balance(tr: Tree): Int = tr match { | 
         | 
   241   case Leaf() => 0  | 
         | 
   242   case Node(_, left, right) => depth(left) - depth(right)  | 
         | 
   243 }  | 
         | 
   244   | 
         | 
   245 balance(insert(t1, 3))  | 
         | 
   246   | 
   451   | 
   247 // another example  | 
   452 // another example  | 
         | 
   453 //=================  | 
   248   | 
   454   | 
   249 abstract class Person  | 
   455 abstract class Person  | 
   250 case class King() extends Person  | 
   456 case class King() extends Person  | 
   251 case class Peer(deg: String, terr: String, succ: Int) extends Person  | 
   457 case class Peer(deg: String, terr: String, succ: Int) extends Person  | 
   252 case class Knight(name: String) extends Person  | 
   458 case class Knight(name: String) extends Person  | 
   253 case class Peasant(name: String) extends Person  | 
   459 case class Peasant(name: String) extends Person  | 
   254 case class Clown() extends Person  | 
   460   | 
   255   | 
   461   | 
   256 def title(p: Person): String = p match { | 
   462 def title(p: Person): String = p match { | 
   257   case King() => "His Majesty the King"  | 
   463   case King() => "His Majesty the King"  | 
   258   case Peer(deg, terr, _) => s"The ${deg} of ${terr}" | 
   464   case Peer(deg, terr, _) => s"The ${deg} of ${terr}" | 
   259   case Knight(name) => s"Sir ${name}" | 
   465   case Knight(name) => s"Sir ${name}" | 
   260   case Peasant(name) => name  | 
   466   case Peasant(name) => name  | 
   261 }  | 
   467 }  | 
         | 
   468   | 
   262   | 
   469   | 
   263 def superior(p1: Person, p2: Person): Boolean = (p1, p2) match { | 
   470 def superior(p1: Person, p2: Person): Boolean = (p1, p2) match { | 
   264   case (King(), _) => true  | 
   471   case (King(), _) => true  | 
   265   case (Peer(_,_,_), Knight(_)) => true  | 
   472   case (Peer(_,_,_), Knight(_)) => true  | 
   266   case (Peer(_,_,_), Peasant(_)) => true  | 
   473   case (Peer(_,_,_), Peasant(_)) => true  | 
   279   | 
   486   | 
   280 println(people.sortWith(superior(_, _)).mkString(", ")) | 
   487 println(people.sortWith(superior(_, _)).mkString(", ")) | 
   281   | 
   488   | 
   282   | 
   489   | 
   283   | 
   490   | 
   284 // Higher-Order Functions  | 
   491   | 
   285 //========================  | 
   492   | 
   286   | 
   493   | 
   287 // functions can take functions as arguments  | 
   494 // Problems with mutability and parallel computations  | 
   288   | 
   495 //====================================================  | 
   289 val lst = (1 to 10).toList  | 
   496   | 
   290   | 
   497 def count_intersection(A: Set[Int], B: Set[Int]) : Int = { | 
   291 def even(x: Int): Boolean = x % 2 == 0  | 
   498   var count = 0  | 
   292 def odd(x: Int): Boolean = x % 2 == 1  | 
   499   for (x <- A; if (B contains x)) count += 1   | 
   293   | 
   500   count  | 
   294 lst.filter(x => even(x))  | 
   501 }  | 
   295 lst.filter(even(_))  | 
   502   | 
   296 lst.filter(even)  | 
   503 val A = (1 to 1000).toSet  | 
   297   | 
   504 val B = (1 to 1000 by 4).toSet  | 
   298 lst.find(_ > 8)  | 
   505   | 
   299   | 
   506 count_intersection(A, B)  | 
   300 def square(x: Int): Int = x * x  | 
   507   | 
   301   | 
   508 // but do not try to add .par to the for-loop above  | 
   302 lst.map(square)  | 
   509   | 
   303   | 
   510   | 
   304 lst.map(square).filter(_ > 4)  | 
   511 //propper parallel version  | 
   305   | 
   512 def count_intersection2(A: Set[Int], B: Set[Int]) : Int =   | 
   306 lst.map(square).filter(_ > 4).map(square)  | 
   513   A.par.count(x => B contains x)  | 
   307   | 
   514   | 
   308 // in my collatz.scala  | 
   515 count_intersection2(A, B)  | 
   309 //(1 to bnd).map(i => (collatz(i), i)).maxBy(_._1)  | 
   516   | 
   310   | 
   517   | 
   311   | 
   518 //for measuring time  | 
   312 // type of functions, for example f: Int => Int  | 
   519 def time_needed[T](n: Int, code: => T) = { | 
   313   | 
   520   val start = System.nanoTime()  | 
   314 def my_map_int(lst: List[Int], f: Int => Int): List[Int] = lst match { | 
   521   for (i <- (0 to n)) code  | 
   315   case Nil => Nil  | 
   522   val end = System.nanoTime()  | 
   316   case x::xs => f(x)::my_map_int(xs, f)  | 
   523   (end - start) / 1.0e9  | 
   317 }  | 
   524 }  | 
   318   | 
   525   | 
   319 my_map_int(lst, square)  | 
   526 val A = (1 to 1000000).toSet  | 
   320   | 
   527 val B = (1 to 1000000 by 4).toSet  | 
   321 // other function types  | 
   528   | 
   322 //  | 
   529 time_needed(10, count_intersection(A, B))  | 
   323 // f1: (Int, Int) => Int  | 
   530 time_needed(10, count_intersection2(A, B))  | 
   324 // f2: List[String] => Option[Int]  | 
   531   | 
   325 // ...   | 
   532   | 
   326   | 
         | 
   327   | 
         | 
   328 def sumOf(f: Int => Int, lst: List[Int]): Int = lst match { | 
         | 
   329   case Nil => 0  | 
         | 
   330   case x::xs => f(x) + sumOf(f, xs)  | 
         | 
   331 }  | 
         | 
   332   | 
         | 
   333 def sum_squares(lst: List[Int]) = sumOf(square, lst)  | 
         | 
   334 def sum_cubes(lst: List[Int])   = sumOf(x => x * x * x, lst)  | 
         | 
   335   | 
         | 
   336 sum_squares(lst)  | 
         | 
   337 sum_cubes(lst)  | 
         | 
   338   | 
         | 
   339 // lets try it factorial  | 
         | 
   340 def fact(n: Int): Int = ...  | 
         | 
   341   | 
         | 
   342 def sum_fact(lst: List[Int]) = sumOf(fact, lst)  | 
         | 
   343 sum_fact(lst)  | 
         | 
   344   | 
         | 
   345 // Avoid being mutable  | 
         | 
   346 //=====================  | 
         | 
   347   | 
         | 
   348 // a student showed me...  | 
         | 
   349 import scala.collection.mutable.ListBuffer  | 
         | 
   350   | 
         | 
   351   | 
         | 
   352   | 
         | 
   353 def collatz_max(bnd: Long): (Long, Long) = { | 
         | 
   354   val colNos = ListBuffer[(Long, Long)]()  | 
         | 
   355   for (i <- (1L to bnd).toList) colNos += ((collatz(i), i))  | 
         | 
   356   colNos.max  | 
         | 
   357 }  | 
         | 
   358   | 
         | 
   359 def collatz_max(bnd: Long): (Long, Long) = { | 
         | 
   360   (1L to bnd).map((i) => (collatz(i), i)).maxBy(_._1)  | 
         | 
   361 }  | 
         | 
   362   | 
         | 
   363 //views -> lazy collection  | 
         | 
   364 def collatz_max(bnd: Long): (Long, Long) = { | 
         | 
   365   (1L to bnd).view.map((i) => (collatz(i), i)).maxBy(_._1)  | 
         | 
   366 }  | 
         | 
   367   | 
         | 
   368 // raises a GC exception  | 
         | 
   369 (1 to 1000000000).filter(_ % 2 == 0).take(10).toList  | 
         | 
   370 // ==> java.lang.OutOfMemoryError: GC overhead limit exceeded  | 
         | 
   371   | 
         | 
   372 (1 to 1000000000).view.filter(_ % 2 == 0).take(10).toList  | 
         | 
   373   | 
   533   | 
   374   | 
   534   | 
   375   | 
   535   | 
   376 // Sudoku  | 
   536 // Sudoku  | 
   377 //========  | 
   537 //========  | 
   397   | 
   557   | 
   398 val allValues = "123456789".toList  | 
   558 val allValues = "123456789".toList  | 
   399 val indexes = (0 to 8).toList  | 
   559 val indexes = (0 to 8).toList  | 
   400   | 
   560   | 
   401   | 
   561   | 
   402   | 
         | 
   403   | 
         | 
   404 def empty(game: String) = game.indexOf(EmptyValue)  | 
   562 def empty(game: String) = game.indexOf(EmptyValue)  | 
   405 def isDone(game: String) = empty(game) == -1   | 
   563 def isDone(game: String) = empty(game) == -1   | 
   406 def emptyPosition(game: String) = (empty(game) % MaxValue, empty(game) / MaxValue)  | 
   564 def emptyPosition(game: String) = (empty(game) % MaxValue, empty(game) / MaxValue)  | 
   407   | 
   565   | 
   408   | 
   566   | 
   409 def get_row(game: String, y: Int) = indexes.map(col => game(y * MaxValue + col))  | 
   567 def get_row(game: String, y: Int) = indexes.map(col => game(y * MaxValue + col))  | 
   410 def get_col(game: String, x: Int) = indexes.map(row => game(x + row * MaxValue))  | 
   568 def get_col(game: String, x: Int) = indexes.map(row => game(x + row * MaxValue))  | 
         | 
   569   | 
         | 
   570 get_row(game0, 3)  | 
         | 
   571 get_col(game0, 0)  | 
   411   | 
   572   | 
   412 def get_box(game: String, pos: Pos): List[Char] = { | 
   573 def get_box(game: String, pos: Pos): List[Char] = { | 
   413     def base(p: Int): Int = (p / 3) * 3  | 
   574     def base(p: Int): Int = (p / 3) * 3  | 
   414     val x0 = base(pos._1)  | 
   575     val x0 = base(pos._1)  | 
   415     val y0 = base(pos._2)  | 
   576     val y0 = base(pos._2)  | 
   416     val ys = (y0 until y0 + 3).toList  | 
   577     val ys = (y0 until y0 + 3).toList  | 
   417     (x0 until x0 + 3).toList.flatMap(x => ys.map(y => game(x + y * MaxValue)))  | 
   578     (x0 until x0 + 3).toList.flatMap(x => ys.map(y => game(x + y * MaxValue)))  | 
   418 }  | 
   579 }  | 
   419   | 
   580   | 
   420   | 
   581 get_box(game0, (0, 0))  | 
   421 //get_row(game0, 0)  | 
   582 get_box(game0, (1, 1))  | 
   422 //get_row(game0, 1)  | 
   583 get_box(game0, (2, 1))  | 
   423 //get_box(game0, (3,1))  | 
   584   | 
   424   | 
   585 // this is not mutable!!  | 
   425 def update(game: String, pos: Int, value: Char): String = game.updated(pos, value)  | 
   586 def update(game: String, pos: Int, value: Char): String = game.updated(pos, value)  | 
   426   | 
   587   | 
   427 def toAvoid(game: String, pos: Pos): List[Char] =   | 
   588 def toAvoid(game: String, pos: Pos): List[Char] =   | 
   428   (get_col(game, pos._1) ++ get_row(game, pos._2) ++ get_box(game, pos))  | 
   589   (get_col(game, pos._1) ++ get_row(game, pos._2) ++ get_box(game, pos))  | 
   429   | 
   590   | 
   430 def candidates(game: String, pos: Pos): List[Char] = allValues diff toAvoid(game,pos)  | 
   591 def candidates(game: String, pos: Pos): List[Char] = allValues.diff(toAvoid(game,pos))  | 
   431   | 
   592   | 
   432 //candidates(game0, (0,0))  | 
   593 //candidates(game0, (0,0))  | 
   433   | 
   594   | 
   434 def pretty(game: String): String = "\n" + (game sliding (MaxValue, MaxValue) mkString "\n")  | 
   595 def pretty(game: String): String =   | 
         | 
   596   "\n" + (game sliding (MaxValue, MaxValue) mkString "\n")  | 
   435   | 
   597   | 
   436 def search(game: String): List[String] = { | 
   598 def search(game: String): List[String] = { | 
   437   if (isDone(game)) List(game)  | 
   599   if (isDone(game)) List(game)  | 
   438   else   | 
   600   else { | 
   439     candidates(game, emptyPosition(game)).map(c => search(update(game, empty(game), c))).toList.flatten  | 
   601     val cs = candidates(game, emptyPosition(game))  | 
   440 }  | 
   602     cs.map(c => search(update(game, empty(game), c))).toList.flatten  | 
   441   | 
   603   }  | 
         | 
   604 }  | 
         | 
   605   | 
         | 
   606 search(game0).map(pretty)  | 
   442   | 
   607   | 
   443 val game1 = """23.915...  | 
   608 val game1 = """23.915...  | 
   444               |...2..54.  | 
   609               |...2..54.  | 
   445               |6.7......  | 
   610               |6.7......  | 
   446               |..1.....9  | 
   611               |..1.....9  |