progs/lecture1.scala
changeset 199 54befaf23648
parent 195 fc3ac7b70a06
child 200 01ee4b576eb2
equal deleted inserted replaced
198:d59c7995bcb2 199:54befaf23648
     1 // Scala Lecture 1
     1 // Scala Lecture 1
     2 //=================
     2 //=================
     3 
     3 
     4 // Value assignments
     4 // Value assignments
     5 // (their names should be lower case)
     5 // (their names should be lower case)
     6 //===================================
     6 //====================================
     7 
     7 
     8 val x = 42
     8 val x = 42
     9 val y = 3 + 4
     9 val y = 3 + 4
    10 val z = x / y
    10 val z = x / y
    11 
    11 
    14 
    14 
    15 
    15 
    16 // Hello World
    16 // Hello World
    17 //=============
    17 //=============
    18 
    18 
    19 // an example of a stand-alone scala file;
    19 // an example of a stand-alone Scala file
    20 // in the coursework students must submit 
    20 // (in the assignments you must submit a plain Scala script)
    21 // plain scala "work-sheets"
       
    22 
    21 
    23 object Hello extends App { 
    22 object Hello extends App { 
    24   println("hello world")
    23   println("hello world")
    25 }
    24 }
    26 
    25 
    27 // can be called with
    26 // can then be called with
    28 //
    27 //
    29 // $> scalac hello-world.scala
    28 // $> scalac hello-world.scala
    30 // $> scala Hello
    29 // $> scala Hello
    31 //
    30 //
    32 // $> java -cp /usr/local/src/scala/lib/scala-library.jar:. Hello
    31 // $> java -cp /usr/local/src/scala/lib/scala-library.jar:. Hello
    33 
       
    34 
    32 
    35 
    33 
    36 
    34 
    37 // Collections
    35 // Collections
    38 //=============
    36 //=============
    51 
    49 
    52 // some alterative syntax for lists
    50 // some alterative syntax for lists
    53 
    51 
    54 1 :: 2 :: 3 :: Nil
    52 1 :: 2 :: 3 :: Nil
    55 List(1, 2, 3) ::: List(4, 5, 6)
    53 List(1, 2, 3) ::: List(4, 5, 6)
       
    54 
       
    55 // Equality is structural
       
    56 //========================
       
    57 val a = "Dave"
       
    58 val b = "Dave"
       
    59 
       
    60 if (a == b) println("equal") else println("unequal")
       
    61 
       
    62 Set(1,2,3) == Set(3,1,2)
       
    63 List(1,2,3) == List(3,1,2)
       
    64 
       
    65 
       
    66 // this applies for "concrete" values;
       
    67 // you cannot compare functions
       
    68 
    56 
    69 
    57 // Printing/Strings
    70 // Printing/Strings
    58 //==================
    71 //==================
    59 
    72 
    60 println("test")
    73 println("test")
    89 List(1,2,3,4).max
   102 List(1,2,3,4).max
    90 List(1,2,3,4).min
   103 List(1,2,3,4).min
    91 List(1,2,3,4).sum
   104 List(1,2,3,4).sum
    92 List(1,2,3,4).take(2).sum
   105 List(1,2,3,4).take(2).sum
    93 List(1,2,3,4).drop(2).sum
   106 List(1,2,3,4).drop(2).sum
    94 List(1,2,3,4,3)indexOf(3)
   107 List(1,2,3,4,3).indexOf(3)
    95 
   108 
    96 "1,2,3,4,5".split(",").mkString("\n")
   109 "1,2,3,4,5".split(",").mkString("\n")
    97 "1,2,3,4,5".split(",3,").mkString("\n")
   110 "1,2,3,4,5".split(",3,").mkString("\n")
    98 
   111 
    99 // Types (slide)
   112 // Types (slide)
   113     Set[Double]
   126     Set[Double]
   114     Pairs: (Int, String)        
   127     Pairs: (Int, String)        
   115     List[(BigInt, String)]
   128     List[(BigInt, String)]
   116 */
   129 */
   117 
   130 
   118 // Smart Strings
       
   119 //===============
       
   120 
       
   121 println(">\n\n<")
       
   122 println(""">\n<""")
       
   123 println("""">\n<"""")
       
   124 
       
   125 /* in Java
       
   126 val lyrics = "Sun dips down, the day has gone. \n" +
       
   127              "Witches, wolves and giants yawn. \n" +
       
   128              "Queen and dragon, troll and gnome: \n" +
       
   129              "tired buddies head for home."
       
   130 */ 
       
   131 
       
   132 val lyrics = """Sun dips down, the day has gone.
       
   133                 |Witches, wolves and giants yawn.
       
   134                 |Queen and dragon, troll and gnome:
       
   135                 |tired buddies head for home.""".stripMargin
       
   136 
       
   137 println(lyrics)
       
   138 
   131 
   139 
   132 
   140 // Pairs/Tuples
   133 // Pairs/Tuples
   141 //==============
   134 //==============
   142 
   135 
   156 def square(x: Int) : Int = x * x
   149 def square(x: Int) : Int = x * x
   157 
   150 
   158 square(6)
   151 square(6)
   159 
   152 
   160 
   153 
   161 
       
   162 // The general scheme for a function: you have to give a type 
   154 // The general scheme for a function: you have to give a type 
   163 // to each argument and a return type of the function
   155 // to each argument and a return type of the function
   164 //
   156 //
   165 //  def fname(arg1: ty1, arg2: ty2,..., argn: tyn): rty = {
   157 //  def fname(arg1: ty1, arg2: ty2,..., argn: tyn): rty = {
   166 //    body 
   158 //    body 
   170 
   162 
   171 // If-Conditionals
   163 // If-Conditionals
   172 //=================
   164 //=================
   173 
   165 
   174 // Scala does not have a then-keyword
   166 // Scala does not have a then-keyword
   175 // both if-else branches need to be presents
   167 // both if-else branches need to be present
   176 
   168 
   177 def fact(n: Int) : Int = 
   169 def fact(n: Int) : Int = 
   178   if (n == 0) 1 else n * fact(n - 1)
   170   if (n == 0) 1 else n * fact(n - 1)
   179 
   171 
   180 
   172 
   207 
   199 
   208 gcd(48, 18)
   200 gcd(48, 18)
   209 
   201 
   210 
   202 
   211 def power(x: Int, n: Int) : Int =
   203 def power(x: Int, n: Int) : Int =
   212   if (n == 0) 1  else x * power(x, n - 1) 
   204   if (n == 0) 1 else x * power(x, n - 1) 
   213 
   205 
   214 power(5, 5)
   206 power(5, 5)
       
   207 
       
   208 
       
   209 // Option type
       
   210 //=============
       
   211 
       
   212 //in Java if something unusually happens, you return null
       
   213 //
       
   214 //in Scala you use Option
       
   215 //   - if the value is present, you use Some(value)
       
   216 //   - if no value is present, you use None
       
   217 
       
   218 
       
   219 List(7,2,3,4,5,6).find(_ < 4)
       
   220 List(5,6,7,8,9).find(_ < 4)
       
   221 
       
   222 
       
   223 
       
   224 // error handling with Options (no exceptions)
       
   225 //
       
   226 //  Try(something).getOrElse(what_to_do_in_case_of_an_exception)
       
   227 //
       
   228 import scala.util._
       
   229 import io.Source
       
   230 
       
   231 val my_url = "https://nms.kcl.ac.uk/christian.urban/"
       
   232 
       
   233 Source.fromURL(my_url).mkString
       
   234 
       
   235 Try(Source.fromURL(my_url).mkString).getOrElse("")
       
   236 
       
   237 Try(Some(Source.fromURL(my_url).mkString)).getOrElse(None)
       
   238 
       
   239 
       
   240 // the same for files
       
   241 Source.fromFile("test.txt").mkString
   215 
   242 
   216 
   243 
   217 // String Interpolations
   244 // String Interpolations
   218 //=======================
   245 //=======================
   219 
   246 
   269      m <- (1 to 3).toList;
   296      m <- (1 to 3).toList;
   270      if ((n + m) % 2 == 0)) yield (n, m)
   297      if ((n + m) % 2 == 0)) yield (n, m)
   271 
   298 
   272 // with patterns
   299 // with patterns
   273 
   300 
   274 for ((m, n) <- List((1, 4), (2, 3), (3, 2), (4, 1))) yield m + n 
   301 val lst = List((1, 4), (2, 3), (3, 2), (4, 1))
   275 
   302 
   276 for (p <- List((1, 4), (2, 3), (3, 2), (4, 1))) yield p._1 + p._2 
   303 for ((m, n) <- lst) yield m + n 
       
   304 
       
   305 for (p <- lst) yield p._1 + p._2 
   277 
   306 
   278 
   307 
   279 // general pattern
   308 // general pattern
   280 
   309 
   281 for (x <- ...) yield {
   310 for (x <- ...) yield {
   289 // has no "yield"
   318 // has no "yield"
   290 
   319 
   291 for (n <- (1 to 10)) println(n)
   320 for (n <- (1 to 10)) println(n)
   292 
   321 
   293 
   322 
   294 
   323 // BTW: a roundabout way of printing out a list, say
   295 // concurrency (ONLY WORKS IN SCALA 2.11.8, not in SCALA 2.12)
   324 val lst = ('a' to 'm').toList
   296 //             (would need to have this wrapped into a function, or
   325 
   297 //              REPL called with scala -Yrepl-class-based)
   326 for (i <- (0 until lst.length)) println(lst(i))
       
   327 
       
   328 // why not?
       
   329 for (c <- lst) println(c)
       
   330 
       
   331 // Aside: concurrency 
       
   332 // (ONLY WORKS OUT-OF-THE-BOX IN SCALA 2.11.8, not in SCALA 2.12)
       
   333 // (would need to have this wrapped into a function, or
       
   334 //  REPL called with scala -Yrepl-class-based)
   298 for (n <- (1 to 10)) println(n)
   335 for (n <- (1 to 10)) println(n)
   299 for (n <- (1 to 10).par) println(n)
   336 for (n <- (1 to 10).par) println(n)
   300 
   337 
   301 
   338 
   302 // for measuring time
   339 // for measuring time
   311 val list = (1 to 1000000).toList
   348 val list = (1 to 1000000).toList
   312 time_needed(10, for (n <- list) yield n + 42)
   349 time_needed(10, for (n <- list) yield n + 42)
   313 time_needed(10, for (n <- list.par) yield n + 42)
   350 time_needed(10, for (n <- list.par) yield n + 42)
   314 
   351 
   315 
   352 
   316 // mutable vs immutable factorial
   353 // Function producing multiple outputs
   317 def fact_mu(n: Long) : Long = {
   354 //=====================================
   318   var result : Long = 1
   355 
   319   var i = 1
   356 def get_ascii(c: Char) : (Char, Int) = (c, c.toInt)
   320   while (i <= n) {
   357 
   321     result = result * i
   358 get_ascii('a')
   322     i = i + 1
   359 
   323   }
   360 
   324   result
   361 
   325 }
   362 // .maxBy, sortBy with pairs
   326 
   363 def get_length(s: String) : (String, Int) = (s, s.length) 
   327 def fact_im(num: Long): Long = {
   364 
   328   if (num == 1) num else
   365 val lst = List("zero", "one", "two", "three", "four", "ten")
   329     num * fact_im(num - 1)
   366 val strs = for (s <- lst) yield get_length(s)
   330 }
   367 
   331 
   368 strs.sortBy(_._2)
   332 def test() = {
   369 strs.sortBy(_._1)
   333   for (i <- (0 to 10).par) yield {
   370 
   334     val l1 = for (n <- (List.fill(100000)(20 to 21)).flatten.par) yield fact_mu(n)
   371 strs.maxBy(_._2)
   335     val l2 = for (n <- (List.fill(100000)(20 to 21)).flatten.par) yield fact_im(n) 
   372 strs.maxBy(_._1)
   336     l1.sum - l2.sum
       
   337   }
       
   338 }
       
   339 
       
   340 (for (i <- (1 to 10)) yield test().sum).sum
       
   341 
       
   342 
       
   343 // Webpages
       
   344 //==========
       
   345 
       
   346 import io.Source
       
   347 
       
   348 // obtaining a webpage
       
   349 val url = """https://nms.kcl.ac.uk/christian.urban/""" 
       
   350 Source.fromURL(url)("ISO-8859-1").mkString
       
   351 
       
   352 
       
   353 // another example
       
   354 //val url = """http://api.postcodes.io/postcodes/CR84LQ""" 
       
   355 
       
   356 
       
   357 // a function for looking up constituency data
       
   358 def consty_lookup(pcode: String) : String = {
       
   359   val url = "http://api.postcodes.io/postcodes/" + pcode
       
   360   Source.fromURL(url).mkString.split(",")(16)
       
   361 }
       
   362 
       
   363 consty_lookup("CR84LQ")
       
   364 consty_lookup("WC2B4BG")
       
   365 
       
   366 
       
   367 val places = 
       
   368   List("CR84LQ", "WC2B4BG", "KY169QT", "CB11LY", "CB39AX")
       
   369 
       
   370 for (s <- places) println(consty_lookup(s))
       
   371 
       
   372 
       
   373 
       
   374 
       
   375 // A Web Crawler 
       
   376 //===============
       
   377 //
       
   378 // the idea is to look for dead links using the
       
   379 // regular expression "https?://[^"]*"
       
   380 
       
   381 import io.Source
       
   382 import scala.util._
       
   383 
       
   384 // gets the first 10K of a web-page
       
   385 def get_page(url: String) : String = {
       
   386   Try(Source.fromURL(url)("ISO-8859-1").take(10000).mkString).
       
   387     getOrElse { println(s"  Problem with: $url"); ""}
       
   388 }
       
   389 
       
   390 // regex for URLs
       
   391 val http_pattern = """"https?://[^"]*"""".r
       
   392 
       
   393 // drops the first and last character from a string
       
   394 def unquote(s: String) = s.drop(1).dropRight(1)
       
   395 
       
   396 def get_all_URLs(page: String): Set[String] = 
       
   397   http_pattern.findAllIn(page).map(unquote).toSet
       
   398 
       
   399 // naive version of crawl - searches until a given depth,
       
   400 // visits pages potentially more than once
       
   401 def crawl(url: String, n: Int) : Unit = {
       
   402   if (n == 0) ()
       
   403   else {
       
   404     println(s"Visiting: $n $url")
       
   405     for (u <- get_all_URLs(get_page(url))) crawl(u, n - 1)
       
   406   }
       
   407 }
       
   408 
       
   409 // some starting URLs for the crawler
       
   410 val startURL = """https://nms.kcl.ac.uk/christian.urban/"""
       
   411 //val startURL = """https://nms.kcl.ac.uk/luc.moreau/index.html"""
       
   412 
       
   413 crawl(startURL, 2)
       
   414 
       
   415 
       
   416 
   373 
   417 // Further Information
   374 // Further Information
   418 //=====================
   375 //=====================
   419 
   376 
   420 // The Scala home page and general information is at
   377 // The Scala home page and general information is at
   495 
   452 
   496 
   453 
   497 
   454 
   498 
   455 
   499 
   456 
   500 // advantage of case classes
   457 
   501 //
   458 
   502 case class Participant(name: String, score: Int, active: Boolean)
   459 
   503 
   460 
   504 val ps = Seq(Participant("Jack", 34, true),
   461 
   505              Participant("Tom", 51, true),
   462 
   506              Participant("Bob", 90, false))
       
   507              
       
   508 ps.filter(_.score < 50).
       
   509    filter(_.active).
       
   510    map(_.copy(active = false))
       
   511 
       
   512 
       
   513 
       
   514 // another example why state is bad...does not work yet
       
   515 
       
   516 // for measuring time
       
   517 def time_needed[T](n: Int, code: => T) = {
       
   518   val start = System.nanoTime()
       
   519   for (i <- (0 to n)) code
       
   520   val end = System.nanoTime()
       
   521   (end - start) / 1.0e9
       
   522 }
       
   523 
       
   524 def santa_state(plan: List[Char]) : Int = {  
       
   525 
       
   526   var floor = 0
       
   527 
       
   528   for (i <- plan.par) {
       
   529     if (i == '(') {
       
   530       floor += 1
       
   531     } else {
       
   532       floor -= 1
       
   533     }
       
   534   }
       
   535   
       
   536   floor
       
   537 }
       
   538 
       
   539 def i(c: Char) = if (c == '(') 1 else -1
       
   540 
       
   541 def santa_imutable(plan: List[Char]) : Int =
       
   542   plan.par.map(i(_)).reduce(_ + _)
       
   543 
       
   544 santa_state("(((((()))))".toList)
       
   545 santa_imutable("(((((()))))".toList)
       
   546 
       
   547 def randomString(length: Int) : String = 
       
   548   List.fill(length)((40 + scala.util.Random.nextInt(2)).toChar)
       
   549 
       
   550 
       
   551 santa_state(randomString(100))
       
   552 
       
   553 val large_string = randomString(3000000)
       
   554 
       
   555 time_needed(10, santa_state(large_string))
       
   556 time_needed(10, santa_imutable(large_string))
       
   557 
       
   558 
       
   559 
       
   560 
       
   561 
       
   562 //=======================
       
   563 // equality is structural
       
   564 val a = "Dave"
       
   565 val b = "Dave"
       
   566 
       
   567 if (a == b) println("equal") else println("unequal")
       
   568 
       
   569 
       
   570 
       
   571 List.fill(10)(math.random)
       
   572 
       
   573 //------------------------
       
   574 
       
   575 
       
   576 for (a <- 0 to 10) {
       
   577   println(a)
       
   578 }
       
   579 
       
   580 for (a <- 0 until 10) {
       
   581   println(a)
       
   582 }
       
   583 
       
   584 for (a <- 0 until 2; b <- 0 to 2) {
       
   585   
       
   586 }
       
   587 
       
   588 output
       
   589 a=0, b=0
       
   590 a=0, b=1
       
   591 a=0, b=2
       
   592 a=1, b=0
       
   593 a=1, b=1
       
   594 a=1, b=2