progs/lecture2.scala
changeset 317 607ceabeeffc
parent 316 8b57dd326a91
child 318 029e2862bb4e
equal deleted inserted replaced
316:8b57dd326a91 317:607ceabeeffc
     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 
       
    14 // String Interpolations
       
    15 //=======================
       
    16 
       
    17 val n = 3
       
    18 println("The square of " + n + " is " + square(n) + ".")
       
    19 
       
    20 println(s"The square of ${n} is ${square(n)}.")
       
    21 
       
    22 
       
    23 // helpful for debugging purposes
       
    24 //
       
    25 //         "The most effective debugging tool is still careful thought, 
       
    26 //          coupled with judiciously placed print statements."
       
    27 //                   — Brian W. Kernighan, in Unix for Beginners (1979)
       
    28 
       
    29 
       
    30 def gcd_db(a: Int, b: Int) : Int = {
       
    31   println(s"Function called with ${a} and ${b}.")
       
    32   if (b == 0) a else gcd_db(b, a % b)
       
    33 }
       
    34 
       
    35 gcd_db(48, 18)
     4 
    36 
     5 
    37 
     6 // The Option Type
    38 // The Option Type
     7 //=================
    39 //=================
     8 
    40 
    59 get_contents("text.txt")
    91 get_contents("text.txt")
    60 get_contents("test.txt")
    92 get_contents("test.txt")
    61 
    93 
    62 
    94 
    63 
    95 
    64 // For-Comprehensions Again
       
    65 //==========================
       
    66 
       
    67 // the first produces a result, while the second does not
       
    68 for (n <- List(1, 2, 3, 4, 5)) yield n * n
       
    69 
       
    70 
       
    71 for (n <- List(1, 2, 3, 4, 5)) println(n)
       
    72 
       
    73 
       
    74 // String Interpolations
       
    75 //=======================
       
    76 
       
    77 val n = 3
       
    78 println("The square of " + n + " is " + square(n) + ".")
       
    79 
       
    80 println(s"The square of ${n} is ${square(n)}.")
       
    81 
       
    82 
       
    83 // helpful for debugging purposes
       
    84 //
       
    85 //         "The most effective debugging tool is still careful thought, 
       
    86 //          coupled with judiciously placed print statements."
       
    87 //                   — Brian W. Kernighan, in Unix for Beginners (1979)
       
    88 
       
    89 
       
    90 def gcd_db(a: Int, b: Int) : Int = {
       
    91   println(s"Function called with ${a} and ${b}.")
       
    92   if (b == 0) a else gcd_db(b, a % b)
       
    93 }
       
    94 
       
    95 gcd_db(48, 18)
       
    96 
       
    97 
       
    98 // Asserts/Testing
       
    99 //=================
       
   100 
       
   101 assert(gcd(48, 18) == 6)
       
   102 
       
   103 assert(gcd(48, 18) == 5, "The gcd test failed")
       
   104 
       
   105 
       
   106 
       
   107 // Higher-Order Functions
       
   108 //========================
       
   109 
       
   110 // functions can take functions as arguments
       
   111 
       
   112 def even(x: Int) : Boolean = x % 2 == 0
       
   113 def odd(x: Int) : Boolean = x % 2 == 1
       
   114 
       
   115 val lst = (1 to 10).toList
       
   116 
       
   117 lst.filter(x => even(x))
       
   118 lst.filter(even(_))
       
   119 lst.filter(even)
       
   120 
       
   121 lst.count(even)
       
   122 
       
   123 
       
   124 lst.find(even)
       
   125 
       
   126 val ps = List((3, 0), (3, 2), (4, 2), (2, 2), (2, 0), (1, 1), (1, 0))
       
   127 
       
   128 lst.sortWith(_ > _)
       
   129 lst.sortWith(_ < _)
       
   130 
       
   131 def lex(x: (Int, Int), y: (Int, Int)) : Boolean = 
       
   132   if (x._1 == y._1) x._2 < y._2 else x._1 < y._1
       
   133 
       
   134 ps.sortWith(lex)
       
   135 
       
   136 ps.sortBy(_._1)
       
   137 ps.sortBy(_._2)
       
   138 
       
   139 ps.maxBy(_._1)
       
   140 ps.maxBy(_._2)
       
   141 
       
   142 
       
   143 
       
   144 // maps (lower-case)
       
   145 //===================
       
   146 
       
   147 def double(x: Int): Int = x + x
       
   148 def square(x: Int): Int = x * x
       
   149 
       
   150 
       
   151 
       
   152 val lst = (1 to 10).toList
       
   153 
       
   154 lst.map(x => (double(x), square(x)))
       
   155 
       
   156 lst.map(square)
       
   157 
       
   158 // this is actually how for-comprehensions 
       
   159 // defined as in Scala
       
   160 
       
   161 lst.map(n => square(n))
       
   162 for (n <- lst) yield square(n)
       
   163 
       
   164 // this can be iterated
       
   165 
       
   166 lst.map(square).filter(_ > 4)
       
   167 
       
   168 lst.map(square).filter(_ > 4).map(square)
       
   169 
       
   170 
       
   171 // lets define our own functions
       
   172 // type of functions, for example f: Int => Int
       
   173 
       
   174 lst.tail
       
   175 
       
   176 def my_map_int(lst: List[Int], f: Int => Int) : List[Int] = {
       
   177   if (lst == Nil) Nil
       
   178   else f(lst.head) :: my_map_int(lst.tail, f)
       
   179 }
       
   180 
       
   181 my_map_int(lst, square)
       
   182 
       
   183 
       
   184 // same function using pattern matching: a kind
       
   185 // of switch statement on steroids (see more later on)
       
   186 
       
   187 def my_map_int(lst: List[Int], f: Int => Int) : List[Int] = lst match {
       
   188   case Nil => Nil
       
   189   case x::xs => f(x)::my_map_int(xs, f)
       
   190 }
       
   191 
       
   192 
       
   193 // other function types
       
   194 //
       
   195 // f1: (Int, Int) => Int
       
   196 // f2: List[String] => Option[Int]
       
   197 // ... 
       
   198 val lst = (1 to 10).toList
       
   199 
       
   200 def sumOf(f: Int => Int, lst: List[Int]): Int = lst match {
       
   201   case Nil => 0
       
   202   case x::xs => f(x) + sumOf(f, xs)
       
   203 }
       
   204 
       
   205 def sum_squares(lst: List[Int]) = sumOf(square, lst)
       
   206 def sum_cubes(lst: List[Int])   = sumOf(x => x * x * x, lst)
       
   207 
       
   208 sum_squares(lst)
       
   209 sum_cubes(lst)
       
   210 
       
   211 // lets try it factorial
       
   212 def fact(n: Int) : Int = 
       
   213   if (n == 0) 1 else n * fact(n - 1)
       
   214 
       
   215 def sum_fact(lst: List[Int]) = sumOf(fact, lst)
       
   216 sum_fact(lst)
       
   217 
       
   218 
       
   219 
       
   220 
       
   221 
       
   222 // Map type (upper-case)
       
   223 //=======================
       
   224 
       
   225 // Note the difference between map and Map
       
   226 
       
   227 def factors(n: Int) : List[Int] =
       
   228   ((1 until n).filter { divisor =>
       
   229       n % divisor == 0
       
   230     }).toList
       
   231 
       
   232 
       
   233 var ls = (1 to 10).toList
       
   234 
       
   235 val facs = ls.map(n => (n, factors(n)))
       
   236 
       
   237 facs.find(_._1 == 4)
       
   238 
       
   239 // works for lists of pairs
       
   240 facs.toMap
       
   241 
       
   242 
       
   243 facs.toMap.get(4)
       
   244 facs.toMap.getOrElse(42, Nil)
       
   245 
       
   246 val facsMap = facs.toMap
       
   247 
       
   248 val facsMap0 = facsMap + (0 -> List(1,2,3,4,5))
       
   249 facsMap0.get(1)
       
   250 
       
   251 val facsMap4 = facsMap + (1 -> List(1,2,3,4,5))
       
   252 facsMap.get(1)
       
   253 facsMap4.get(1)
       
   254 
       
   255 val ls = List("one", "two", "three", "four", "five")
       
   256 ls.groupBy(_.length)
       
   257 
       
   258 ls.groupBy(_.length).get(2)
       
   259 
       
   260 
       
   261 
       
   262 // Option type (again)
       
   263 //=====================
       
   264 
       
   265 // remember, in Java if something unusually happens, 
       
   266 // you return null;
       
   267 //
       
   268 // in Scala you use Option
       
   269 //   - if the value is present, you use Some(value)
       
   270 //   - if no value is present, you use None
       
   271 
       
   272 
       
   273 List(7,2,3,4,5,6).find(_ < 4)
       
   274 List(5,6,7,8,9).find(_ < 4)
       
   275 
       
   276 // operations on options
    96 // operations on options
   277 
    97 
   278 val lst = List(None, Some(1), Some(2), None, Some(3))
    98 val lst = List(None, Some(1), Some(2), None, Some(3))
   279 
    99 
   280 lst.flatten
   100 lst.flatten
   284 
   104 
   285 Some(1).isDefined
   105 Some(1).isDefined
   286 None.isDefined
   106 None.isDefined
   287 
   107 
   288 
   108 
   289 None.isDefined
       
   290 
       
   291 val ps = List((3, 0), (3, 2), (4, 2), (2, 0), (1, 0), (1, 1))
   109 val ps = List((3, 0), (3, 2), (4, 2), (2, 0), (1, 0), (1, 1))
       
   110 
       
   111 // division where possible
   292 
   112 
   293 for ((x, y) <- ps) yield {
   113 for ((x, y) <- ps) yield {
   294   if (y == 0) None else Some(x / y)
   114   if (y == 0) None else Some(x / y)
   295 }
   115 }
   296 
   116 
   299 val lst = List(None, Some(1), Some(2), None, Some(3))
   119 val lst = List(None, Some(1), Some(2), None, Some(3))
   300 
   120 
   301 for (x <- lst) yield x.getOrElse(0)
   121 for (x <- lst) yield x.getOrElse(0)
   302 
   122 
   303 
   123 
   304 
       
   305 
       
   306 // error handling with Option (no exceptions)
       
   307 //
       
   308 //  Try(something).getOrElse(what_to_do_in_an_exception)
       
   309 //
       
   310 import scala.util._
       
   311 import io.Source
       
   312 
       
   313 
       
   314 Source.fromURL("""http://www.inf.ucl.ac.uk/staff/urbanc/""").mkString
       
   315 
       
   316 Try(Source.fromURL("""http://www.inf.kcl.ac.uk/staff/urbanc/""").mkString).getOrElse("")
       
   317 
       
   318 Try(Some(Source.fromURL("""http://www.inf.kcl.ac.uk/staff/urbanc/""").mkString)).getOrElse(None)
       
   319 
       
   320 
       
   321 // a function that turns strings into numbers (similar to .toInt)
       
   322 Integer.parseInt("12u34")
       
   323 
       
   324 
       
   325 def get_me_an_int(s: String) : Option[Int] = 
       
   326  Try(Some(Integer.parseInt(s))).getOrElse(None)
       
   327 
       
   328 val lst = List("12345", "foo", "5432", "bar", "x21", "456")
       
   329 for (x <- lst) yield get_me_an_int(x)
       
   330 
       
   331 // summing up all the numbers
       
   332 
       
   333 lst.map(get_me_an_int).flatten.sum
       
   334 lst.map(get_me_an_int).flatten.sum
       
   335 
       
   336 
       
   337 lst.flatMap(get_me_an_int).map(_.toString)
       
   338 
   124 
   339 
   125 
   340 // This may not look any better than working with null in Java, but to
   126 // This may not look any better than working with null in Java, but to
   341 // see the value, you have to put yourself in the shoes of the
   127 // see the value, you have to put yourself in the shoes of the
   342 // consumer of the get_me_an_int function, and imagine you didn't
   128 // consumer of the get_me_an_int function, and imagine you didn't
   352 // even Scala is not immune to problems like this:
   138 // even Scala is not immune to problems like this:
   353 
   139 
   354 List(5,6,7,8,9).indexOf(7)
   140 List(5,6,7,8,9).indexOf(7)
   355 List(5,6,7,8,9).indexOf(10)
   141 List(5,6,7,8,9).indexOf(10)
   356 List(5,6,7,8,9)(-1)
   142 List(5,6,7,8,9)(-1)
       
   143 
       
   144 
       
   145 
       
   146 
       
   147 // Higher-Order Functions
       
   148 //========================
       
   149 
       
   150 // functions can take functions as arguments
       
   151 
       
   152 def even(x: Int) : Boolean = x % 2 == 0
       
   153 def odd(x: Int) : Boolean = x % 2 == 1
       
   154 
       
   155 val lst = (1 to 10).toList
       
   156 
       
   157 lst.filter(x => even(x))
       
   158 lst.filter(even(_))
       
   159 lst.filter(even)
       
   160 
       
   161 lst.count(even)
       
   162 
       
   163 
       
   164 lst.find(even)
       
   165 
       
   166 val ps = List((3, 0), (3, 2), (4, 2), (2, 2), (2, 0), (1, 1), (1, 0))
       
   167 
       
   168 lst.sortWith(_ > _)
       
   169 lst.sortWith(_ < _)
       
   170 
       
   171 def lex(x: (Int, Int), y: (Int, Int)) : Boolean = 
       
   172   if (x._1 == y._1) x._2 < y._2 else x._1 < y._1
       
   173 
       
   174 ps.sortWith(lex)
       
   175 
       
   176 ps.sortBy(_._1)
       
   177 ps.sortBy(_._2)
       
   178 
       
   179 ps.maxBy(_._1)
       
   180 ps.maxBy(_._2)
       
   181 
       
   182 
       
   183 
       
   184 // maps (lower-case)
       
   185 //===================
       
   186 
       
   187 def double(x: Int): Int = x + x
       
   188 def square(x: Int): Int = x * x
       
   189 
       
   190 
       
   191 val lst = (1 to 10).toList
       
   192 
       
   193 lst.map(x => (double(x), square(x)))
       
   194 
       
   195 lst.map(square)
       
   196 
       
   197 // this is actually how for-comprehensions 
       
   198 // defined as in Scala
       
   199 
       
   200 lst.map(n => square(n))
       
   201 for (n <- lst) yield square(n)
       
   202 
       
   203 // this can be iterated
       
   204 
       
   205 lst.map(square).filter(_ > 4)
       
   206 
       
   207 lst.map(square).filter(_ > 4).map(square)
       
   208 
       
   209 
       
   210 // lets define our own functions
       
   211 // type of functions, for example f: Int => Int
       
   212 
       
   213 lst.tail
       
   214 
       
   215 def my_map_int(lst: List[Int], f: Int => Int) : List[Int] = {
       
   216   if (lst == Nil) Nil
       
   217   else f(lst.head) :: my_map_int(lst.tail, f)
       
   218 }
       
   219 
       
   220 my_map_int(lst, square)
       
   221 
       
   222 
       
   223 // same function using pattern matching: a kind
       
   224 // of switch statement on steroids (see more later on)
       
   225 
       
   226 def my_map_int(lst: List[Int], f: Int => Int) : List[Int] = lst match {
       
   227   case Nil => Nil
       
   228   case x::xs => f(x)::my_map_int(xs, f)
       
   229 }
       
   230 
       
   231 
       
   232 // other function types
       
   233 //
       
   234 // f1: (Int, Int) => Int
       
   235 // f2: List[String] => Option[Int]
       
   236 // ... 
       
   237 val lst = (1 to 10).toList
       
   238 
       
   239 def sumOf(f: Int => Int, lst: List[Int]): Int = lst match {
       
   240   case Nil => 0
       
   241   case x::xs => f(x) + sumOf(f, xs)
       
   242 }
       
   243 
       
   244 def sum_squares(lst: List[Int]) = sumOf(square, lst)
       
   245 def sum_cubes(lst: List[Int])   = sumOf(x => x * x * x, lst)
       
   246 
       
   247 sum_squares(lst)
       
   248 sum_cubes(lst)
       
   249 
       
   250 // lets try it factorial
       
   251 def fact(n: Int) : Int = 
       
   252   if (n == 0) 1 else n * fact(n - 1)
       
   253 
       
   254 def sum_fact(lst: List[Int]) = sumOf(fact, lst)
       
   255 sum_fact(lst)
       
   256 
       
   257 
       
   258 
       
   259 // if you like verbosity, you can full-specify the literal. 
       
   260 // Don't go telling that to people, though
       
   261 (1 to 100).filter((x: Int) => x % 2 == 0).sum 
       
   262 
       
   263 // As x is known to be an Int anyway, you can omit that part
       
   264 (1 to 100).filter(x => x % 2 == 0).sum
       
   265 
       
   266 // As each parameter (only x in this case) is passed only once
       
   267 // you can use the wizardy placeholder syntax
       
   268 (1 to 100).filter(_ % 2 == 0).sum
       
   269 
       
   270 // But if you want to re-use your literal, you can also put it in a value
       
   271 // In this case, explicit types are required because there's nothing to infer from
       
   272 val isEven = (x: Int) => x % 2 == 0
       
   273 (1 to 100).filter(isEven).sum
       
   274 
       
   275 
       
   276 
       
   277 // Option Type again
       
   278 //===================
       
   279 
       
   280 // a function that turns strings into numbers (similar to .toInt)
       
   281 Integer.parseInt("12u34")
       
   282 
       
   283 
       
   284 def get_me_an_int(s: String) : Option[Int] = 
       
   285  Try(Some(Integer.parseInt(s))).getOrElse(None)
       
   286 
       
   287 val lst = List("12345", "foo", "5432", "bar", "x21", "456")
       
   288 for (x <- lst) yield get_me_an_int(x)
       
   289 
       
   290 // summing up all the numbers
       
   291 
       
   292 lst.map(get_me_an_int).flatten.sum
       
   293 lst.map(get_me_an_int).flatten.sum
       
   294 
       
   295 lst.flatMap(get_me_an_int).sum
       
   296 
       
   297 
       
   298 
       
   299 
       
   300 // Map type (upper-case)
       
   301 //=======================
       
   302 
       
   303 // Note the difference between map and Map
       
   304 
       
   305 def factors(n: Int) : List[Int] =
       
   306   ((1 until n).filter { divisor =>
       
   307       n % divisor == 0
       
   308     }).toList
       
   309 
       
   310 
       
   311 var ls = (1 to 10).toList
       
   312 
       
   313 val facs = ls.map(n => (n, factors(n)))
       
   314 
       
   315 facs.find(_._1 == 4)
       
   316 
       
   317 // works for lists of pairs
       
   318 facs.toMap
       
   319 
       
   320 
       
   321 facs.toMap.get(4)
       
   322 facs.toMap.getOrElse(42, Nil)
       
   323 
       
   324 val facsMap = facs.toMap
       
   325 
       
   326 val facsMap0 = facsMap + (0 -> List(1,2,3,4,5))
       
   327 facsMap0.get(1)
       
   328 
       
   329 val facsMap4 = facsMap + (1 -> List(1,2,3,4,5))
       
   330 facsMap.get(1)
       
   331 facsMap4.get(1)
       
   332 
       
   333 val ls = List("one", "two", "three", "four", "five")
       
   334 ls.groupBy(_.length)
       
   335 
       
   336 ls.groupBy(_.length).get(2)
       
   337 
   357 
   338 
   358 
   339 
   359 
   340 
   360 // Pattern Matching
   341 // Pattern Matching
   361 //==================
   342 //==================
   805 
   786 
   806 
   787 
   807 
   788 
   808 
   789 
   809 
   790 
   810 // if you like verbosity, you can full-specify the literal. 
   791 
   811 // Don't go telling that to people, though
       
   812 (1 to 100).filter((x: Int) => x % 2 == 0).sum 
       
   813 
       
   814 // As x is known to be an Int anyway, you can omit that part
       
   815 (1 to 100).filter(x => x % 2 == 0).sum
       
   816 
       
   817 // As each parameter (only x in this case) is passed only once
       
   818 // you can use the wizardy placeholder syntax
       
   819 (1 to 100).filter(_ % 2 == 0).sum
       
   820 
       
   821 // But if you want to re-use your literal, you can also put it in a value
       
   822 // In this case, explicit types are required because there's nothing to infer from
       
   823 val isEven: (x: Int) => x % 2 == 0
       
   824 (1 to 100).filter(isEven).sum