|      1 // Scala Lecture 2 |      1 // Scala Lecture 2 | 
|      2 //================= |      2 //================= | 
|      3  |      3  | 
|      4 // For-Comprehensions Again |         | 
|      5 //========================== |         | 
|      6  |         | 
|      7 // the first produces a result, while the second does not |         | 
|      8 for (n <- List(1, 2, 3, 4, 5)) yield n * n |         | 
|      9  |         | 
|     10  |         | 
|     11 for (n <- List(1, 2, 3, 4, 5)) println(n) |         | 
|     12  |         | 
|     13  |      4  | 
|     14 // String Interpolations |      5 // String Interpolations | 
|     15 //======================= |      6 //======================= | 
|     16  |      7  | 
|         |      8  | 
|     17 def cube(n: Int) : Int = n * n * n |      9 def cube(n: Int) : Int = n * n * n | 
|     18  |     10  | 
|     19 val n = 3 |     11 val n = 3 | 
|     20 println("The cube of " + n + " is " + cube(n) + ".") |     12 println("The cube of " + n + " is " + cube(n) + ".") | 
|     21  |     13  | 
|     22 println(s"The cube of ${n} is ${cube(n)}.") |     14 println(s"The cube of $n is ${cube(n)}.") | 
|     23  |     15  | 
|     24 // or even |     16 // or even | 
|     25  |     17  | 
|     26 println(s"The cube of ${n} is ${n * n * n}.") |     18 println(s"The cube of $n is ${n * n * n}.") | 
|     27  |     19  | 
|     28 // helpful for debugging purposes |     20 // helpful for debugging purposes | 
|     29 // |     21 // | 
|     30 //         "The most effective debugging tool is still careful thought,  |     22 //     "The most effective debugging tool is still careful  | 
|     31 //          coupled with judiciously placed print statements." |     23 //          thought, coupled with judiciously placed print  | 
|     32 //                   — Brian W. Kernighan, in Unix for Beginners (1979) |     24 //                                             statements." | 
|         |     25 //       — Brian W. Kernighan, in Unix for Beginners (1979) | 
|     33  |     26  | 
|     34  |     27  | 
|     35 def gcd_db(a: Int, b: Int) : Int = { |     28 def gcd_db(a: Int, b: Int) : Int = { | 
|     36   println(s"Function called with ${a} and ${b}.") |     29   println(s"Function called with $a and $b.") | 
|     37   if (b == 0) a else gcd_db(b, a % b) |     30   if (b == 0) a else gcd_db(b, a % b) | 
|     38 } |     31 } | 
|     39  |     32  | 
|     40 gcd_db(48, 18) |     33 gcd_db(48, 18) | 
|         |     34  | 
|         |     35  | 
|         |     36  | 
|         |     37 // you can also implement your own string interpolations | 
|         |     38  | 
|         |     39 import scala.language.implicitConversions | 
|         |     40 import scala.language.reflectiveCalls | 
|         |     41  | 
|         |     42 implicit def sring_inters(sc: StringContext) = new { | 
|         |     43     def i(args: Any*): String = s"\t${sc.s(args:_*)}\n" | 
|         |     44     def l(args: Any*): String = s"${sc.s(args:_*)}:\n" | 
|         |     45 } | 
|         |     46  | 
|         |     47 // this allows you to write things like | 
|         |     48  | 
|         |     49 i"add ${3+2}"  | 
|         |     50 l"some_fresh_name" | 
|         |     51  | 
|     41  |     52  | 
|     42  |     53  | 
|     43 // The Option Type |     54 // The Option Type | 
|     44 //================= |     55 //================= | 
|     45  |     56  | 
|     46 // in Java, if something unusually happens, you return null or  |     57 // in Java, if something unusually happens, you return null  | 
|     47 // raise an exception |     58 // or raise an exception | 
|     48 // |     59 // | 
|     49 //in Scala you use Options instead |     60 //in Scala you use Options instead | 
|     50 //   - if the value is present, you use Some(value) |     61 //   - if the value is present, you use Some(value) | 
|     51 //   - if no value is present, you use None |     62 //   - if no value is present, you use None | 
|     52  |     63  | 
|     53  |     64  | 
|     54 List(7,2,3,4,5,6).find(_ < 4) |     65 List(7,2,3,4,5,6).find(_ < 4) | 
|     55 List(5,6,7,8,9).find(_ < 4) |     66 List(5,6,7,8,9).find(_ < 4) | 
|     56  |     67  | 
|         |     68 // Int:      ..., 0, 1, 2,... | 
|         |     69 // Boolean:  true false | 
|         |     70 // | 
|         |     71 // List[Int]: Nil, List(_)  | 
|         |     72 // | 
|         |     73 // Option[Int]: None, Some(0), Some(1), ... | 
|         |     74 // Option[...]: None, Some(_) | 
|         |     75  | 
|         |     76 def safe_div(x: Int, y: Int) : Option[Int] =  | 
|         |     77   if (y == 0) None else Some(x / y) | 
|         |     78  | 
|         |     79 List(1,2,3,4,5,6).indexOf(7) | 
|         |     80  | 
|         |     81 def my_min(ls: List[Int]) : Option[Int] = ls.minOption | 
|         |     82  | 
|         |     83 my_min(List(1,2,3,4)) | 
|         |     84  | 
|     57  |     85  | 
|     58 // better error handling with Options (no exceptions) |     86 // better error handling with Options (no exceptions) | 
|     59 // |     87 // | 
|     60 //  Try(something).getOrElse(what_to_do_in_case_of_an_exception) |     88 //  Try(something).getOrElse(what_to_do_in_case_of_an_exception) | 
|     61 // |     89 // | 
|     62  |     90  | 
|     63 import scala.util._ |     91 import scala.util._ | 
|     64 import io.Source |     92 import io.Source | 
|     65  |     93  | 
|     66 val my_url = "https://nms.kcl.ac.uk/christian.urban/" |     94 val my_url = "https://nms.kcl.ac.uk/christian.urban2/" | 
|     67  |     95  | 
|     68 Source.fromURL(my_url).mkString |     96 Source.fromURL(my_url)("ISO-8859-1").mkString | 
|     69  |     97  | 
|     70 Try(Source.fromURL(my_url).mkString).getOrElse("") |     98 Try(Source.fromURL(my_url)("ISO-8859-1").mkString).getOrElse("") | 
|     71  |     99  | 
|     72 Try(Some(Source.fromURL(my_url).mkString)).getOrElse(None) |    100 Try(Some(Source.fromURL(my_url)("ISO-8859-1").mkString)).getOrElse(None) | 
|     73  |    101  | 
|     74  |    102  | 
|     75 // the same for files |    103 // the same for files | 
|     76 Try(Some(Source.fromFile("text.txt").mkString)).getOrElse(None) |    104 Try(Some(Source.fromFile("test.txt")("ISO-8859-1").mkString)).getOrElse(None) | 
|     77  |    105  | 
|     78  |    106  | 
|     79 // how to implement a function for reading  |    107 // how to implement a function for reading  | 
|     80 // (lines) something from files... |    108 // (lines) something from files... | 
|     81 // |    109 // | 
|     82 def get_contents(name: String) : List[String] =  |    110 def get_contents(name: String) : List[String] =  | 
|     83   Source.fromFile(name).getLines.toList |    111   Source.fromFile(name)("ISO-8859-1").getLines.toList | 
|     84  |    112  | 
|     85 get_contents("text.txt") |    113 get_contents("text.txt") | 
|     86 get_contents("test.txt") |    114 get_contents("test.txt") | 
|     87  |    115  | 
|     88 // slightly better - return Nil |    116 // slightly better - return Nil | 
|     89 def get_contents(name: String) : List[String] =  |    117 def get_contents(name: String) : List[String] =  | 
|     90   Try(Source.fromFile(name).getLines.toList).getOrElse(List()) |    118   Try(Source.fromFile(name)("ISO-8859-1").getLines.toList).getOrElse(List()) | 
|     91  |    119  | 
|     92 get_contents("text.txt") |    120 get_contents("text.txt") | 
|     93  |    121  | 
|     94 // much better - you record in the type that things can go wrong  |    122 // much better - you record in the type that things can go wrong  | 
|     95 def get_contents(name: String) : Option[List[String]] =  |    123 def get_contents(name: String) : Option[List[String]] =  | 
|     96   Try(Some(Source.fromFile(name).getLines.toList)).getOrElse(None) |    124   Try(Some(Source.fromFile(name)("ISO-8859-1").getLines.toList)).getOrElse(None) | 
|     97  |    125  | 
|     98 get_contents("text.txt") |    126 get_contents("text.txt") | 
|     99 get_contents("test.txt") |    127 get_contents("test.txt") | 
|    100  |    128  | 
|    101  |    129  | 
|    109 None.get |    137 None.get | 
|    110  |    138  | 
|    111 Some(1).isDefined |    139 Some(1).isDefined | 
|    112 None.isDefined |    140 None.isDefined | 
|    113  |    141  | 
|    114  |    142 for (x <- lst) yield x.getOrElse(0) | 
|    115 val ps = List((3, 0), (4, 2), (6, 2), (2, 0), (1, 0), (1, 1)) |    143  | 
|         |    144  | 
|         |    145  | 
|         |    146 val ps = List((3, 0), (4, 2), (6, 2),  | 
|         |    147               (2, 0), (1, 0), (1, 1)) | 
|    116  |    148  | 
|    117 // division where possible |    149 // division where possible | 
|    118  |    150  | 
|    119 for ((x, y) <- ps) yield { |    151 for ((x, y) <- ps) yield { | 
|    120   if (y == 0) None else Some(x / y) |    152   if (y == 0) None else Some(x / y) | 
|    121 } |    153 } | 
|    122  |    154  | 
|         |    155  | 
|         |    156  | 
|    123 // getOrElse is for setting a default value |    157 // getOrElse is for setting a default value | 
|    124  |    158  | 
|    125 val lst = List(None, Some(1), Some(2), None, Some(3)) |    159 val lst = List(None, Some(1), Some(2), None, Some(3)) | 
|    126  |    160  | 
|    127 for (x <- lst) yield x.getOrElse(0) |    161  | 
|    128  |    162  | 
|    129  |    163  | 
|    130 // a function that turns strings into numbers (similar to .toInt) |    164 // a function that turns strings into numbers  | 
|    131 Integer.parseInt("12u34") |    165 // (similar to .toInt) | 
|         |    166 Integer.parseInt("1234") | 
|    132  |    167  | 
|    133  |    168  | 
|    134 def get_me_an_int(s: String) : Option[Int] =  |    169 def get_me_an_int(s: String) : Option[Int] =  | 
|    135  Try(Some(Integer.parseInt(s))).getOrElse(None) |    170  Try(Some(Integer.parseInt(s))).getOrElse(None) | 
|    136  |    171  |