diff -r e689375abcc1 -r 22705d22c105 progs/lecture3.scala --- a/progs/lecture3.scala Fri Nov 23 01:52:37 2018 +0000 +++ b/progs/lecture3.scala Tue Nov 27 21:41:59 2018 +0000 @@ -7,7 +7,7 @@ // // the idea is to look for links using the // regular expression "https?://[^"]*" and for -// email addresses using another regex. +// email addresses using yet another regex. import io.Source import scala.util._ @@ -22,9 +22,8 @@ val http_pattern = """"https?://[^"]*"""".r val email_pattern = """([a-z0-9_\.-]+)@([\da-z\.-]+)\.([a-z\.]{2,6})""".r -//email_pattern.findAllIn -// ("foo bla christian@kcl.ac.uk 1234567").toList - +// val s = "foo bla christian@kcl.ac.uk 1234567" +// email_pattern.findAllIn(s).toList // drops the first and last character from a string def unquote(s: String) = s.drop(1).dropRight(1) @@ -34,6 +33,7 @@ // naive version of crawl - searches until a given depth, // visits pages potentially more than once + def crawl(url: String, n: Int) : Set[String] = { if (n == 0) Set() else { @@ -41,36 +41,92 @@ val page = get_page(url) val new_emails = email_pattern.findAllIn(page).toSet new_emails ++ - (for (u <- get_all_URLs(page)) yield crawl(u, n - 1)).flatten + (for (u <- get_all_URLs(page).par) yield crawl(u, n - 1)).flatten } } // some starting URLs for the crawler val startURL = """https://nms.kcl.ac.uk/christian.urban/""" - crawl(startURL, 2) // User-defined Datatypes and Pattern Matching -//============================================ - +//============================================= abstract class Exp -case class N(n: Int) extends Exp +case class N(n: Int) extends Exp // for numbers case class Plus(e1: Exp, e2: Exp) extends Exp case class Times(e1: Exp, e2: Exp) extends Exp +def string(e: Exp) : String = e match { + case N(n) => n.toString + case Plus(e1, e2) => "(" + string(e1) + " + " + string(e2) + ")" + case Times(e1, e2) => "(" + string(e1) + " * " + string(e2) + ")" +} +val e = Plus(N(9), Times(N(3), N(4))) +println(string(e)) + +def eval(e: Exp) : Int = e match { + case N(n) => n + case Plus(e1, e2) => eval(e1) + eval(e2) + case Times(e1, e2) => eval(e1) * eval(e2) +} + +def simp(e: Exp) : Exp = e match { + case N(n) => N(n) + case Plus(e1, e2) => (simp(e1), simp(e2)) match { + case (N(0), e2s) => e2s + case (e1s, N(0)) => e1s + case (e1s, e2s) => Plus(e1s, e2s) + } + case Times(e1, e2) => (simp(e1), simp(e2)) match { + case (N(0), _) => N(0) + case (_, N(0)) => N(0) + case (N(1), e2s) => e2s + case (e1s, N(1)) => e1s + case (e1s, e2s) => Times(e1s, e2s) + } +} + +println(eval(e)) -// string of an Exp -// eval of an Exp -// simp an Exp -// Tokens -// Reverse Polish Notation -// compute RP -// transform RP into Exp -// process RP string and generate Exp +val e2 = Times(Plus(N(0), N(1)), Plus(N(0), N(9))) +println(string(e2)) +println(string(simp(e2))) + +// Tokens and Reverse Polish Notation +abstract class Token +case class T(n: Int) extends Token +case object PL extends Token +case object TI extends Token + +def rp(e: Exp) : List[Token] = e match { + case N(n) => List(T(n)) + case Plus(e1, e2) => rp(e1) ::: rp(e2) ::: List(PL) + case Times(e1, e2) => rp(e1) ::: rp(e2) ::: List(TI) +} +println(string(e2)) +println(rp(e2)) + +def comp(ls: List[Token], st: List[Int]) : Int = (ls, st) match { + case (Nil, st) => st.head + case (T(n)::rest, st) => comp(rest, n::st) + case (PL::rest, n1::n2::st) => comp(rest, n1 + n2::st) + case (TI::rest, n1::n2::st) => comp(rest, n1 * n2::st) +} + +comp(rp(e), Nil) + +def proc(s: String) : Token = s match { + case "+" => PL + case "*" => TI + case _ => T(s.toInt) +} + +comp("1 2 + 4 * 5 + 3 +".split(" ").toList.map(proc), Nil) + @@ -159,6 +215,11 @@ def fact(n: Long): Long = if (n == 0) 1 else n * fact(n - 1) +def factB(n: BigInt): BigInt = + if (n == 0) 1 else n * factB(n - 1) + +factB(100000) + fact(10) //ok fact(10000) // produces a stackoverflow @@ -166,7 +227,7 @@ if (n == 0) acc else factT(n - 1, n * acc) factT(10, 1) -factT(100000, 1) +println(factT(100000, 1)) // there is a flag for ensuring a function is tail recursive import scala.annotation.tailrec @@ -192,6 +253,8 @@ // the first n prefixes of xs // for 1 => include xs + + def moves(xs: List[Int], n: Int) : List[List[Int]] = (xs, n) match { case (Nil, _) => Nil case (xs, 0) => Nil @@ -204,7 +267,6 @@ moves(List(5,1,0), 5) // checks whether a jump tour exists at all -// in the second case it needs to be < instead of <= def search(xs: List[Int]) : Boolean = xs match { case Nil => true @@ -235,14 +297,12 @@ case Nil => Nil case (x::xs) => { val children = moves(xs, x) - val results = children.flatMap((cs) => jumps(cs).map(x :: _)) + val results = children.map((cs) => jumps(cs).map(x :: _)).flatten if (xs.length < x) List(x) :: results else results } } - - -jumps(List(5,3,2,5,1,1)) +println(jumps(List(5,3,2,5,1,1)).minBy(_.length)) jumps(List(3,5,1,2,1,2,1)) jumps(List(3,5,1,2,3,4,1)) jumps(List(3,5,1,0,0,0,1)) @@ -315,7 +375,8 @@ //get_row(game0, 0) //get_row(game0, 1) -//get_box(game0, (3,1)) +//get_col(game0, 0) +//get_box(game0, (3, 1)) // this is not mutable!! @@ -326,20 +387,19 @@ (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)) + allValues.diff(toAvoid(game, pos)) //candidates(game0, (0,0)) def pretty(game: String): String = - "\n" + (game sliding (MaxValue, MaxValue) mkString "\n") + "\n" + (game.sliding(MaxValue, MaxValue).mkString("\n")) -///////////////////// -// not tail recursive + def search(game: String): List[String] = { if (isDone(game)) List(game) else { val cs = candidates(game, emptyPosition(game)) - cs.map(c => search(update(game, empty(game), c))).toList.flatten + cs.par.map(c => search(update(game, empty(game), c))).toList.flatten } } @@ -379,8 +439,6 @@ |9724...5.""".stripMargin.replaceAll("\\n", "") - - search(game1).map(pretty) search(game3).map(pretty) search(game2).map(pretty)