diff -r d59c7995bcb2 -r 54befaf23648 progs/lecture1.scala --- a/progs/lecture1.scala Wed Nov 07 12:08:01 2018 +0000 +++ b/progs/lecture1.scala Thu Nov 08 23:42:03 2018 +0000 @@ -3,7 +3,7 @@ // Value assignments // (their names should be lower case) -//=================================== +//==================================== val x = 42 val y = 3 + 4 @@ -16,15 +16,14 @@ // Hello World //============= -// an example of a stand-alone scala file; -// in the coursework students must submit -// plain scala "work-sheets" +// an example of a stand-alone Scala file +// (in the assignments you must submit a plain Scala script) object Hello extends App { println("hello world") } -// can be called with +// can then be called with // // $> scalac hello-world.scala // $> scala Hello @@ -33,7 +32,6 @@ - // Collections //============= List(1,2,3,1) @@ -54,6 +52,21 @@ 1 :: 2 :: 3 :: Nil List(1, 2, 3) ::: List(4, 5, 6) +// Equality is structural +//======================== +val a = "Dave" +val b = "Dave" + +if (a == b) println("equal") else println("unequal") + +Set(1,2,3) == Set(3,1,2) +List(1,2,3) == List(3,1,2) + + +// this applies for "concrete" values; +// you cannot compare functions + + // Printing/Strings //================== @@ -91,7 +104,7 @@ List(1,2,3,4).sum List(1,2,3,4).take(2).sum List(1,2,3,4).drop(2).sum -List(1,2,3,4,3)indexOf(3) +List(1,2,3,4,3).indexOf(3) "1,2,3,4,5".split(",").mkString("\n") "1,2,3,4,5".split(",3,").mkString("\n") @@ -115,26 +128,6 @@ List[(BigInt, String)] */ -// Smart Strings -//=============== - -println(">\n\n<") -println(""">\n<""") -println("""">\n<"""") - -/* in Java -val lyrics = "Sun dips down, the day has gone. \n" + - "Witches, wolves and giants yawn. \n" + - "Queen and dragon, troll and gnome: \n" + - "tired buddies head for home." -*/ - -val lyrics = """Sun dips down, the day has gone. - |Witches, wolves and giants yawn. - |Queen and dragon, troll and gnome: - |tired buddies head for home.""".stripMargin - -println(lyrics) // Pairs/Tuples @@ -158,7 +151,6 @@ square(6) - // The general scheme for a function: you have to give a type // to each argument and a return type of the function // @@ -172,7 +164,7 @@ //================= // Scala does not have a then-keyword -// both if-else branches need to be presents +// both if-else branches need to be present def fact(n: Int) : Int = if (n == 0) 1 else n * fact(n - 1) @@ -209,11 +201,46 @@ def power(x: Int, n: Int) : Int = - if (n == 0) 1 else x * power(x, n - 1) + if (n == 0) 1 else x * power(x, n - 1) power(5, 5) +// Option type +//============= + +//in Java if something unusually happens, you return null +// +//in Scala you use Option +// - if the value is present, you use Some(value) +// - if no value is present, you use None + + +List(7,2,3,4,5,6).find(_ < 4) +List(5,6,7,8,9).find(_ < 4) + + + +// error handling with Options (no exceptions) +// +// Try(something).getOrElse(what_to_do_in_case_of_an_exception) +// +import scala.util._ +import io.Source + +val my_url = "https://nms.kcl.ac.uk/christian.urban/" + +Source.fromURL(my_url).mkString + +Try(Source.fromURL(my_url).mkString).getOrElse("") + +Try(Some(Source.fromURL(my_url).mkString)).getOrElse(None) + + +// the same for files +Source.fromFile("test.txt").mkString + + // String Interpolations //======================= @@ -271,9 +298,11 @@ // with patterns -for ((m, n) <- List((1, 4), (2, 3), (3, 2), (4, 1))) yield m + n +val lst = List((1, 4), (2, 3), (3, 2), (4, 1)) -for (p <- List((1, 4), (2, 3), (3, 2), (4, 1))) yield p._1 + p._2 +for ((m, n) <- lst) yield m + n + +for (p <- lst) yield p._1 + p._2 // general pattern @@ -291,10 +320,18 @@ for (n <- (1 to 10)) println(n) +// BTW: a roundabout way of printing out a list, say +val lst = ('a' to 'm').toList -// concurrency (ONLY WORKS IN SCALA 2.11.8, not in SCALA 2.12) -// (would need to have this wrapped into a function, or -// REPL called with scala -Yrepl-class-based) +for (i <- (0 until lst.length)) println(lst(i)) + +// why not? +for (c <- lst) println(c) + +// Aside: concurrency +// (ONLY WORKS OUT-OF-THE-BOX IN SCALA 2.11.8, not in SCALA 2.12) +// (would need to have this wrapped into a function, or +// REPL called with scala -Yrepl-class-based) for (n <- (1 to 10)) println(n) for (n <- (1 to 10).par) println(n) @@ -313,106 +350,26 @@ time_needed(10, for (n <- list.par) yield n + 42) -// mutable vs immutable factorial -def fact_mu(n: Long) : Long = { - var result : Long = 1 - var i = 1 - while (i <= n) { - result = result * i - i = i + 1 - } - result -} - -def fact_im(num: Long): Long = { - if (num == 1) num else - num * fact_im(num - 1) -} - -def test() = { - for (i <- (0 to 10).par) yield { - val l1 = for (n <- (List.fill(100000)(20 to 21)).flatten.par) yield fact_mu(n) - val l2 = for (n <- (List.fill(100000)(20 to 21)).flatten.par) yield fact_im(n) - l1.sum - l2.sum - } -} - -(for (i <- (1 to 10)) yield test().sum).sum - +// Function producing multiple outputs +//===================================== -// Webpages -//========== - -import io.Source - -// obtaining a webpage -val url = """https://nms.kcl.ac.uk/christian.urban/""" -Source.fromURL(url)("ISO-8859-1").mkString - - -// another example -//val url = """http://api.postcodes.io/postcodes/CR84LQ""" - +def get_ascii(c: Char) : (Char, Int) = (c, c.toInt) -// a function for looking up constituency data -def consty_lookup(pcode: String) : String = { - val url = "http://api.postcodes.io/postcodes/" + pcode - Source.fromURL(url).mkString.split(",")(16) -} - -consty_lookup("CR84LQ") -consty_lookup("WC2B4BG") - - -val places = - List("CR84LQ", "WC2B4BG", "KY169QT", "CB11LY", "CB39AX") - -for (s <- places) println(consty_lookup(s)) +get_ascii('a') - -// A Web Crawler -//=============== -// -// the idea is to look for dead links using the -// regular expression "https?://[^"]*" +// .maxBy, sortBy with pairs +def get_length(s: String) : (String, Int) = (s, s.length) -import io.Source -import scala.util._ - -// gets the first 10K of a web-page -def get_page(url: String) : String = { - Try(Source.fromURL(url)("ISO-8859-1").take(10000).mkString). - getOrElse { println(s" Problem with: $url"); ""} -} - -// regex for URLs -val http_pattern = """"https?://[^"]*"""".r +val lst = List("zero", "one", "two", "three", "four", "ten") +val strs = for (s <- lst) yield get_length(s) -// drops the first and last character from a string -def unquote(s: String) = s.drop(1).dropRight(1) - -def get_all_URLs(page: String): Set[String] = - http_pattern.findAllIn(page).map(unquote).toSet +strs.sortBy(_._2) +strs.sortBy(_._1) -// naive version of crawl - searches until a given depth, -// visits pages potentially more than once -def crawl(url: String, n: Int) : Unit = { - if (n == 0) () - else { - println(s"Visiting: $n $url") - for (u <- get_all_URLs(get_page(url))) crawl(u, n - 1) - } -} - -// some starting URLs for the crawler -val startURL = """https://nms.kcl.ac.uk/christian.urban/""" -//val startURL = """https://nms.kcl.ac.uk/luc.moreau/index.html""" - -crawl(startURL, 2) - - +strs.maxBy(_._2) +strs.maxBy(_._1) // Further Information //===================== @@ -497,98 +454,9 @@ -// advantage of case classes -// -case class Participant(name: String, score: Int, active: Boolean) - -val ps = Seq(Participant("Jack", 34, true), - Participant("Tom", 51, true), - Participant("Bob", 90, false)) - -ps.filter(_.score < 50). - filter(_.active). - map(_.copy(active = false)) - - - -// another example why state is bad...does not work yet - -// for measuring time -def time_needed[T](n: Int, code: => T) = { - val start = System.nanoTime() - for (i <- (0 to n)) code - val end = System.nanoTime() - (end - start) / 1.0e9 -} - -def santa_state(plan: List[Char]) : Int = { - - var floor = 0 - - for (i <- plan.par) { - if (i == '(') { - floor += 1 - } else { - floor -= 1 - } - } - - floor -} - -def i(c: Char) = if (c == '(') 1 else -1 - -def santa_imutable(plan: List[Char]) : Int = - plan.par.map(i(_)).reduce(_ + _) - -santa_state("(((((()))))".toList) -santa_imutable("(((((()))))".toList) - -def randomString(length: Int) : String = - List.fill(length)((40 + scala.util.Random.nextInt(2)).toChar) - - -santa_state(randomString(100)) - -val large_string = randomString(3000000) - -time_needed(10, santa_state(large_string)) -time_needed(10, santa_imutable(large_string)) -//======================= -// equality is structural -val a = "Dave" -val b = "Dave" -if (a == b) println("equal") else println("unequal") - - - -List.fill(10)(math.random) - -//------------------------ - - -for (a <- 0 to 10) { - println(a) -} - -for (a <- 0 until 10) { - println(a) -} - -for (a <- 0 until 2; b <- 0 to 2) { - -} - -output -a=0, b=0 -a=0, b=1 -a=0, b=2 -a=1, b=0 -a=1, b=1 -a=1, b=2