diff -r 6fa91be92d0c -r 9b88f9e04344 progs/lecture2.scala --- a/progs/lecture2.scala Thu Nov 17 03:38:53 2016 +0000 +++ b/progs/lecture2.scala Thu Nov 17 11:17:04 2016 +0000 @@ -2,30 +2,10 @@ //================= -// Implicits -//=========== -// -// for example adding your own methods to Strings: -// imagine you want to increment strings, like -// -// "HAL".increment -// -// you can avoid ugly fudges, like a MyString, by -// using implicit conversions - - -implicit class MyString(s: String) { - def increment = for (c <- s) yield (c + 1).toChar -} - -"HAL".increment - - - // Option type //============= -//in Java if something unusually happens, you return null +//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 @@ -49,25 +29,28 @@ if (y == 0) None else Some(x / y) } -// getOrElse is to set a default value +// getOrElse is for setting a default value val lst = List(None, Some(1), Some(2), None, Some(3)) -for (x <- lst) yield x getOrElse 0 +for (x <- lst) yield x.getOrElse(0) + + +// error handling with option (no exceptions) +// +// Try(something).getOrElse(what_to_do_in_an_exception) +// import scala.util._ import io.Source -// error handling with option -// -// Try(something).getOrElse(what_to_do_in_an_exception) -Source.fromURL("""http://www.inf.kcl.ac.uk/staff/urbanccc/""").mkString +Source.fromURL("""http://www.inf.kcl.ac.uk/staff/urbanc/""").mkString Try(Source.fromURL("""http://www.inf.kcl.ac.uk/staff/urbanc/""").mkString).getOrElse("") Try(Some(Source.fromURL("""http://www.inf.kcl.ac.uk/staff/urbanc/""").mkString)).getOrElse(None) - +// a function that turns strings into numbers Integer.parseInt("12u34") def get_me_an_int(s: String): Option[Int] = @@ -86,10 +69,9 @@ // write that function. // // In Java, if you didn't write this function, you'd have to depend on -// the Javadoc of the get_me_an_int. If you didn't look at the Javadoc -// for the Java, you might not know that get_me_an_int could return a -// null, and your code could potentially throw a NullPointerException. - +// the Javadoc of the get_me_an_int. If you didn't look at the Javadoc, +// you might not know that get_me_an_int could return a null, and your +// code could potentially throw a NullPointerException. @@ -103,6 +85,25 @@ +// Implicits +//=========== +// +// for example adding your own methods to Strings: +// imagine you want to increment strings, like +// +// "HAL".increment +// +// you can avoid ugly fudges, like a MyString, by +// using implicit conversions + + +implicit class MyString(s: String) { + def increment = for (c <- s) yield (c + 1).toChar +} + +"HAL".increment + + // No return in Scala //==================== @@ -121,6 +122,7 @@ sumq(List(1,2,3,4)) + // last expression in a function is the return statement def square(x: Int): Int = { println(s"The argument is ${x}.") @@ -155,6 +157,13 @@ } + + + + + + + def my_flatten(lst: List[Option[Int]]): List[Int] = lst match { case Nil => Nil case None::xs => my_flatten(xs) @@ -170,6 +179,8 @@ case _ => "many" } +get_me_a_string(0) + // User-defined Datatypes //======================== @@ -177,6 +188,7 @@ case class Node(elem: Int, left: Tree, right: Tree) extends Tree case class Leaf() extends Tree + def insert(tr: Tree, n: Int): Tree = tr match { case Leaf() => Node(n, Leaf(), Leaf()) case Node(m, left, right) => @@ -223,12 +235,14 @@ } val people = List(Knight("David"), - Peer("Duke", "Norfolk", 42), + Peer("Duke", "Norfolk", 84), Peasant("Christian"), King(), Clown()) -println(people.sortWith(superior(_, _))) +println(people.sortWith(superior(_, _)).mkString(", ")) + + // Higher-Order Functions //======================== @@ -258,7 +272,8 @@ //(1 to bnd).map(i => (collatz(i), i)).maxBy(_._1) -// type of functions +// type of functions, for example f: Int => Int + def my_map_int(lst: List[Int], f: Int => Int): List[Int] = lst match { case Nil => Nil case x::xs => f(x)::my_map_int(xs, f) @@ -266,6 +281,12 @@ my_map_int(lst, square) +// other function types +// +// f1: (Int, Int) => Int +// f2: List[String] => Option[Int] +// ... + def sumOf(f: Int => Int, lst: List[Int]): Int = lst match { case Nil => 0 @@ -278,7 +299,11 @@ sum_squares(lst) sum_cubes(lst) +def fact(n: Int): Int = + if (n == 0) 1 else n * fact(n - 1) +def sum_fact(lst: List[Int]) = sumOf(fact, lst) +sum_fact(lst) // Avoid being mutable //===================== @@ -307,9 +332,16 @@ (1 to 1000000000).view.filter(_ % 2 == 0).take(10).toList + + // Sudoku //======== +// THE POINT OF THIS CODE IS NOT TO BE SUPER +// EFFICIENT AND FAST, just explaining exhaustive +// depth-first search + + val game0 = """.14.6.3.. |62...4..9 |.8..5.6.. @@ -320,7 +352,6 @@ |1..5...92 |..7.9.41.""".stripMargin.replaceAll("\\n", "") - type Pos = (Int, Int) val EmptyValue = '.' val MaxValue = 9 @@ -328,14 +359,18 @@ val allValues = "123456789".toList val indexes = (0 to 8).toList -def empty(game: String) = game.indexOf(EmptyValue) -def emptyPosition(game: String) = (empty(game) % MaxValue, empty(game) / MaxValue) -def isDone(game: String) = empty(game) == -1 + + -def row(game: String, y: Int): List[Char] = indexes.map(col => game(y * MaxValue + col)) -def col(game: String, x: Int): List[Char] = indexes.map(row => game(x + row * MaxValue)) +def empty(game: String) = game.indexOf(EmptyValue) +def isDone(game: String) = empty(game) == -1 +def emptyPosition(game: String) = (empty(game) % MaxValue, empty(game) / MaxValue) + -def box(game: String, pos: Pos): List[Char] = { +def get_row(game: String, y: Int) = indexes.map(col => game(y * MaxValue + col)) +def get_col(game: String, x: Int) = indexes.map(row => game(x + row * MaxValue)) + +def get_box(game: String, pos: Pos): List[Char] = { def base(p: Int): Int = (p / 3) * 3 val x0 = base(pos._1) val y0 = base(pos._2) @@ -344,14 +379,14 @@ } -//row(game0, 0) -//row(game0, 1) -//box(game0, (3,1)) +//get_row(game0, 0) +//get_row(game0, 1) +//get_box(game0, (3,1)) def update(game: String, pos: Int, value: Char): String = game.updated(pos, value) def toAvoid(game: String, pos: Pos): List[Char] = - (col(game, pos._1) ++ row(game, pos._2) ++ box(game, pos)).distinct + (get_col(game, pos._1) ++ get_row(game, pos._2) ++ get_box(game, pos)) def candidates(game: String, pos: Pos): List[Char] = allValues diff toAvoid(game,pos) @@ -362,7 +397,7 @@ def search(game: String): List[String] = { if (isDone(game)) List(game) else - candidates(game, emptyPosition(game)).par.map(c => search(update(game, empty(game), c))).toList.flatten + candidates(game, emptyPosition(game)).map(c => search(update(game, empty(game), c))).toList.flatten } @@ -376,6 +411,7 @@ |.16..7... |...329..1""".stripMargin.replaceAll("\\n", "") + // game that is in the hard category val game2 = """8........ |..36..... @@ -398,6 +434,7 @@ |.3.5...8. |9724...5.""".stripMargin.replaceAll("\\n", "") + search(game0).map(pretty) search(game1).map(pretty) @@ -410,7 +447,7 @@ } search(game2).map(pretty) -search(game3).distinct.map(pretty).length +search(game3).distinct.length time_needed(3, search(game2)) time_needed(3, search(game3))