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   |