// Scala Lecture 1+ −
//=================+ −
+ −
// Value assignments+ −
// (their names should be lower case)+ −
//===================================+ −
+ −
val x = 42+ −
val y = 3 + 4+ −
val z = x / y+ −
+ −
+ −
// (you cannot reassign values: z = 9 will give an error)+ −
+ −
+ −
// Hello World+ −
//=============+ −
+ −
// an example of a stand-alone scala file;+ −
// in the coursework students must submit + −
// plain scala "work-sheets"+ −
+ −
object Hello extends App { + −
println("hello world")+ −
}+ −
+ −
// can be called with+ −
//+ −
// $> scalac hello-world.scala+ −
// $> scala Hello+ −
//+ −
// $> java -cp /usr/local/src/scala/lib/scala-library.jar:. Hello+ −
+ −
+ −
+ −
+ −
// Collections+ −
//=============+ −
List(1,2,3,1)+ −
Set(1,2,3,1)+ −
+ −
1 to 10+ −
(1 to 10).toList+ −
+ −
(1 until 10).toList+ −
+ −
// an element in a list+ −
val lst = List(1, 2, 3, 1)+ −
lst(0)+ −
lst(2)+ −
+ −
// some alterative syntax for lists+ −
+ −
1::2::3::Nil+ −
List(1, 2, 3) ::: List(4, 5, 6)+ −
+ −
// Printing/Strings+ −
//==================+ −
+ −
println("test")+ −
+ −
val tst = "This is a " + "test\n" + −
println(tst)+ −
+ −
val lst = List(1,2,3,1)+ −
+ −
println(lst.toString)+ −
println(lst.mkString("\n"))+ −
+ −
println(lst.mkString(", "))+ −
+ −
// some methods take more than one argument+ −
println(lst.mkString("[", ",", "]"))+ −
+ −
+ −
// Conversion methods+ −
//====================+ −
+ −
List(1,2,3,1).toString+ −
List(1,2,3,1).toSet+ −
"hello".toList+ −
1.toDouble+ −
+ −
+ −
// useful list methods+ −
+ −
List(1,2,3,4).length+ −
List(1,2,3,4).reverse+ −
List(1,2,3,4).max+ −
List(1,2,3,4).min+ −
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)+ −
+ −
"1,2,3,4,5".split(",").mkString("\n")+ −
"1,2,3,4,5".split(",3,").mkString("\n")+ −
+ −
// Types (slide)+ −
//=======+ −
+ −
/* Scala is a strongly typed language+ −
+ −
* some base types+ −
+ −
Int, Long, BigInt, Float, Double+ −
String, Char+ −
Boolean+ −
+ −
* some compound types + −
+ −
List[Int],+ −
Set[Double]+ −
Pairs: (Int, String) + −
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+ −
//==============+ −
+ −
val p = (1, "one")+ −
p._1+ −
p._2+ −
+ −
val t = (4,1,2,3)+ −
t._4+ −
+ −
+ −
// Function Definitions+ −
//======================+ −
+ −
def incr(x: Int) : Int = x + 1+ −
def double(x: Int) : Int = x + x+ −
def square(x: Int) : Int = x * x+ −
+ −
square(6)+ −
+ −
+ −
+ −
// The general scheme for a function: you have to give a type + −
// to each argument and a return type of the function+ −
//+ −
// def fname(arg1: ty1, arg2: ty2,..., argn: tyn): rty = {+ −
// body + −
// }+ −
+ −
+ −
+ −
// If-Conditionals+ −
//=================+ −
+ −
def fact(n: Int) : Int = + −
if (n == 0) 1 else n * fact(n - 1)+ −
+ −
+ −
fact(5)+ −
fact(150)+ −
+ −
/* boolean operators+ −
+ −
== equals+ −
! not+ −
&& || and, or+ −
*/+ −
+ −
+ −
def fact2(n: BigInt): BigInt = + −
if (n == 0) 1 else n * fact2(n - 1)+ −
+ −
fact2(150)+ −
+ −
+ −
def fib(n: Int): Int =+ −
if (n == 0) 1 else+ −
if (n == 1) 1 else fib(n - 1) + fib(n - 2)+ −
+ −
+ −
//gcd - Euclid's algorithm+ −
+ −
def gcd(a: Int, b: Int) : Int =+ −
if (b == 0) a else gcd(b, a % b)+ −
+ −
gcd(48, 18)+ −
+ −
+ −
def power(x: Int, n: Int) : Int =+ −
if (n == 0) 1 else x * power(x, n - 1) + −
+ −
power(5, 5)+ −
+ −
+ −
// String Interpolations+ −
//=======================+ −
+ −
val n = 3+ −
println("The square of " + n + " is " + square(n) + ".")+ −
+ −
println(s"The square of ${n} is ${square(n)}.")+ −
+ −
+ −
+ −
def gcd_db(a: Int, b: Int) : Int = {+ −
println(s"Function called with ${a} and ${b}.")+ −
if (b == 0) a else gcd_db(b, a % b)+ −
}+ −
+ −
gcd_db(48, 18)+ −
+ −
+ −
// Asserts/Testing+ −
//================+ −
+ −
assert(gcd(48, 18) == 6)+ −
+ −
assert(gcd(48, 18) == 5, "The gcd test failed")+ −
+ −
+ −
// For-Comprehensions (not For-Loops)+ −
//====================================+ −
+ −
for (n <- (1 to 10).toList) yield square(n)+ −
+ −
for (n <- (1 to 10).toList; + −
m <- (1 to 10).toList) yield m * n+ −
+ −
+ −
val mult_table = + −
for (n <- (1 to 10).toList; + −
m <- (1 to 10).toList) yield m * n+ −
+ −
mult_table.sliding(10,10).mkString("\n")+ −
+ −
+ −
// with if-predicates+ −
+ −
for (n <- (1 to 3).toList; + −
m <- (1 to 3).toList;+ −
if (n + m) % 2 == 0) yield (n, m)+ −
+ −
for (n <- (1 to 3).toList; + −
m <- (1 to 3).toList;+ −
if ((n + m) % 2 == 0)) yield (n, m)+ −
+ −
// with patterns+ −
+ −
for ((m, n) <- List((1, 4), (2, 3), (3, 2), (4, 1))) yield m + n + −
+ −
for (p <- List((1, 4), (2, 3), (3, 2), (4, 1))) yield p._1 + p._2 + −
+ −
+ −
+ −
// with only a side-effect (no list is produced),+ −
// has no "yield"+ −
+ −
for (n <- (1 to 10)) println(n)+ −
+ −
+ −
+ −
+ −
+ −
+ −
// 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 (n <- (1 to 10)) println(n)+ −
for (n <- (1 to 10).par) println(n)+ −
+ −
+ −
// 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+ −
}+ −
+ −
+ −
val list = (1 to 1000000).toList+ −
time_needed(10, for (n <- list) yield n + 42)+ −
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+ −
}+ −
}+ −
+ −
test().sum+ −
println(l1.sum - l2.sum)+ −
+ −
// 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""" + −
+ −
+ −
// 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))+ −
+ −
+ −
+ −
+ −
// A Web Crawler + −
//===============+ −
//+ −
// the idea is to look for dead links using the+ −
// regular expression "https?://[^"]*"+ −
+ −
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+ −
+ −
// 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+ −
+ −
// 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)+ −
+ −
+ −
+ −
// Further Information+ −
//=====================+ −
+ −
// The Scala home page and general information is at+ −
//+ −
// http://www.scala-lang.org+ −
// http://docs.scala-lang.org+ −
//+ −
//+ −
// It should be fairly easy to install the Scala binary and+ −
// run Scala on the commandline. There are also at least + −
// four IDEs you can use with Scala:+ −
//+ −
// (0) Some general information about setting up IDEs+ −
// with Scala support can be found at+ −
//+ −
// http://docs.scala-lang.org/getting-started.html + −
//+ −
//+ −
// (1) Eclipse for Scala (one big bundle)+ −
//+ −
// http://scala-ide.org/download/sdk.html+ −
// + −
// (2) IntelliJ (needs additional Plugins)+ −
//+ −
// https://www.jetbrains.com/idea/+ −
// http://docs.scala-lang.org/getting-started-intellij-track/getting-started-with-scala-in-intellij.html + −
//+ −
// (3) Sublime (not free, but unlimited trial period; + −
// needs Scala and SublimeREPL plugin)+ −
//+ −
// https://www.sublimetext.com+ −
//+ −
// (4) Emacs (old-fashioned, but reliable)+ −
//+ −
// https://www.gnu.org/software/emacs/+ −
//+ −
// I use the old scala-tool support for Emacs distributed at+ −
//+ −
// https://github.com/scala/scala-tool-support/tree/master/tool-support/emacs + −
//+ −
// but there is also support for the newer Ensime Scala Mode+ −
//+ −
// http://ensime.org/editors/emacs/scala-mode/ + −
// + −
// There is also Scala support in the Atom editor, but my+ −
// experience is mixed. People also use Scala with Vim and Jedit.+ −
// Finally there is an online editor specifically designed for + −
// running Scala applications (but do not blame mne if you lose all + −
// what you typed in):+ −
//+ −
// https://scalafiddle.io + −
//+ −
//+ −
//+ −
// All of the IDEs above support a REPL for Scala. Some of them have+ −
// the very nifty feature of a Scala Worksheet -- you just save your+ −
// file and it will be automatically evaluated and the result pasted+ −
// into your file. However, this way of writing Scala code never worked+ −
// for me. I just use the REPL.+ −
//+ −
//+ −
// Scala Library Docs+ −
//====================+ −
//+ −
// http://www.scala-lang.org/api/current/+ −
//+ −
// Scala Tutorials+ −
//+ −
// http://docs.scala-lang.org/tutorials/+ −
//+ −
// There are also a massive number of Scala tutorials on youtube+ −
// and there are tons of books and free material.+ −
//+ −
+ −
+ −
+ −
+ −
+ −
+ −
+ −
+ −
+ −
// 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) = + −
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))+ −