|      1 // Scala Lecture 2 |      1 // Scala Lecture 2 | 
|      2 //================= |      2 //================= | 
|      3   |      3   | 
|      4  |      4 // - Options | 
|      5 // String Interpolations |      5 // - Higher-Order Functions (short-hand notation) | 
|      6 //======================= |      6 // - maps (behind for-comprehensions) | 
|      7  |      7 // - Pattern-Matching | 
|      8 def cube(n: Int) : Int = n * n * n |      8 // - Recursion | 
|      9  |         | 
|     10 val n = 3 |         | 
|     11 println("The cube of " + n + " is " + cube(n) + ".") |         | 
|     12  |         | 
|     13 println(s"The cube of $n is ${cube(n)}.") |         | 
|     14  |         | 
|     15 // or even |         | 
|     16  |         | 
|     17 println(s"The cube of $n is ${n * n * n}.") |         | 
|     18  |         | 
|     19 // helpful for debugging purposes |         | 
|     20 // |         | 
|     21 //     "The most effective debugging tool is still careful  |         | 
|     22 //          thought, coupled with judiciously placed print  |         | 
|     23 //                                             statements." |         | 
|     24 //       — Brian W. Kernighan, in Unix for Beginners (1979) |         | 
|     25  |         | 
|     26  |         | 
|     27 def gcd_db(a: Int, b: Int) : Int = { |         | 
|     28   println(s"Function called with $a and $b.") |         | 
|     29   if (b == 0) a else gcd_db(b, a % b) |         | 
|     30 } |         | 
|     31  |         | 
|     32 gcd_db(48, 18) |         | 
|     33  |         | 
|     34  |         | 
|     35  |         | 
|     36 // you can also implement your own string interpolations |         | 
|     37  |         | 
|     38 import scala.language.implicitConversions |         | 
|     39 import scala.language.reflectiveCalls |         | 
|     40  |         | 
|     41 implicit def sring_inters(sc: StringContext) = new { |         | 
|     42     def i(args: Any*): String = s"\t${sc.s(args:_*)}\n" |         | 
|     43     def l(args: Any*): String = s"${sc.s(args:_*)}:\n" |         | 
|     44 } |         | 
|     45  |         | 
|     46 // this allows you to write things like |         | 
|     47  |         | 
|     48 i"add ${3+2}"  |         | 
|     49 l"some_fresh_name" |         | 
|     50  |         | 
|     51  |         | 
|     52  |      9  | 
|     53 // The Option Type |     10 // The Option Type | 
|     54 //================= |     11 //================= | 
|     55  |     12  | 
|     56 // in Java, if something unusually happens, you return null  |     13 // in Java, if something unusually happens, you return null  | 
|     77   if (y == 0) None else Some(x / y) |     34   if (y == 0) None else Some(x / y) | 
|     78  |     35  | 
|     79 safe_div(10 + 5, 4 - 1)   |     36 safe_div(10 + 5, 4 - 1)   | 
|     80  |     37  | 
|     81 List(1,2,3,4,5,6).indexOf(7) |     38 List(1,2,3,4,5,6).indexOf(7) | 
|         |     39 List[Int]().min | 
|     82 List[Int]().minOption |     40 List[Int]().minOption | 
|     83  |     41  | 
|     84 def my_min(ls: List[Int]) : Option[Int] =  |     42 def my_min(ls: List[Int]) : Option[Int] =  | 
|     85   ls.minOption |     43   ls.minOption | 
|     86  |     44  | 
|     90 // better error handling with Options (no exceptions) |     48 // better error handling with Options (no exceptions) | 
|     91 // |     49 // | 
|     92 //  Try(something).getOrElse(what_to_do_in_case_of_an_exception) |     50 //  Try(something).getOrElse(what_to_do_in_case_of_an_exception) | 
|     93 // |     51 // | 
|     94  |     52  | 
|     95 import scala.util._ |     53 import scala.util._      // Try,... | 
|     96 import io.Source |     54 import io.Source         // fromURL | 
|     97  |     55  | 
|     98 val my_url = "https://nms.kcl.ac.uk/christian.urban/" |     56 val my_url = "https://nms.kcl.ac.uk/christian.urban/" | 
|     99  |     57  | 
|    100 Source.fromURL(my_url)("ISO-8859-1").mkString |     58 Source.fromURL(my_url)("ISO-8859-1").mkString | 
|    101 Source.fromURL(my_url)("ISO-8859-1").getLines().toList |     59 Source.fromURL(my_url)("ISO-8859-1").getLines().toList | 
|    397  |    355  | 
|    398  |    356  | 
|    399 // Pattern Matching |    357 // Pattern Matching | 
|    400 //================== |    358 //================== | 
|    401  |    359  | 
|    402 // A powerful tool which is supposed to come to Java in  |    360 // A powerful tool which has even landed in Java during  | 
|    403 // a few years time (https://www.youtube.com/watch?v=oGll155-vuQ). |    361 // the last few years (https://inside.java/2021/06/13/podcast-017/). | 
|    404 // ...Scala already has it for many years ;o) |    362 // ...Scala already has it for many years and the concept is | 
|         |    363 // older than your friendly lecturer, that is stone old  ;o) | 
|    405  |    364  | 
|    406 // The general schema: |    365 // The general schema: | 
|    407 // |    366 // | 
|    408 //    expression match { |    367 //    expression match { | 
|    409 //       case pattern1 => expression1 |    368 //       case pattern1 => expression1 | 
|    418   lst match { |    377   lst match { | 
|    419     case Nil => Nil |    378     case Nil => Nil | 
|    420     case x::xs => f(x)::my_map_int(xs, f) |    379     case x::xs => f(x)::my_map_int(xs, f) | 
|    421   } |    380   } | 
|    422  |    381  | 
|    423 def my_map_option(o: Option[Int], f: Int => Int) : Option[Int] =  |    382 def my_map_option(opt: Option[Int], f: Int => Int) : Option[Int] =  | 
|    424   o match { |    383   opt match { | 
|    425     case None => None |    384     case None => None | 
|    426     case Some(x) => Some(f(x)) |    385     case Some(x) => Some(f(x)) | 
|    427   } |    386   } | 
|    428  |    387  | 
|    429 my_map_option(None, x => x * x) |    388 my_map_option(None, x => x * x) |