| 222 |      1 | // Scala Lecture 4
 | 
|  |      2 | //=================
 | 
|  |      3 | 
 | 
|  |      4 | 
 | 
| 325 |      5 | // expressions (essentially trees)
 | 
|  |      6 | 
 | 
|  |      7 | abstract class Exp
 | 
|  |      8 | case class N(n: Int) extends Exp                  // for numbers
 | 
|  |      9 | case class Plus(e1: Exp, e2: Exp) extends Exp
 | 
|  |     10 | case class Times(e1: Exp, e2: Exp) extends Exp
 | 
|  |     11 | 
 | 
|  |     12 | def string(e: Exp) : String = e match {
 | 
|  |     13 |   case N(n) => s"$n"
 | 
|  |     14 |   case Plus(e1, e2) => s"(${string(e1)} + ${string(e2)})" 
 | 
|  |     15 |   case Times(e1, e2) => s"(${string(e1)} * ${string(e2)})"
 | 
|  |     16 | }
 | 
|  |     17 | 
 | 
|  |     18 | val e = Plus(N(9), Times(N(3), N(4)))
 | 
|  |     19 | println(string(e))
 | 
|  |     20 | 
 | 
|  |     21 | def eval(e: Exp) : Int = e match {
 | 
|  |     22 |   case N(n) => n
 | 
|  |     23 |   case Plus(e1, e2) => eval(e1) + eval(e2) 
 | 
|  |     24 |   case Times(e1, e2) => eval(e1) * eval(e2) 
 | 
|  |     25 | }
 | 
|  |     26 | 
 | 
|  |     27 | println(eval(e))
 | 
|  |     28 | 
 | 
|  |     29 | // simplification rules:
 | 
|  |     30 | // e + 0, 0 + e => e 
 | 
|  |     31 | // e * 0, 0 * e => 0
 | 
|  |     32 | // e * 1, 1 * e => e
 | 
|  |     33 | 
 | 
|  |     34 | def simp(e: Exp) : Exp = e match {
 | 
|  |     35 |   case N(n) => N(n)
 | 
|  |     36 |   case Plus(e1, e2) => (simp(e1), simp(e2)) match {
 | 
|  |     37 |     case (N(0), e2s) => e2s
 | 
|  |     38 |     case (e1s, N(0)) => e1s
 | 
|  |     39 |     case (e1s, e2s) => Plus(e1s, e2s)
 | 
|  |     40 |   }  
 | 
|  |     41 |   case Times(e1, e2) => (simp(e1), simp(e2)) match {
 | 
|  |     42 |     case (N(0), _) => N(0)
 | 
|  |     43 |     case (_, N(0)) => N(0)
 | 
|  |     44 |     case (N(1), e2s) => e2s
 | 
|  |     45 |     case (e1s, N(1)) => e1s
 | 
|  |     46 |     case (e1s, e2s) => Times(e1s, e2s)
 | 
|  |     47 |   }  
 | 
|  |     48 | }
 | 
|  |     49 | 
 | 
|  |     50 | 
 | 
|  |     51 | val e2 = Times(Plus(N(0), N(1)), Plus(N(0), N(9)))
 | 
|  |     52 | println(string(e2))
 | 
|  |     53 | println(string(simp(e2)))
 | 
|  |     54 | 
 | 
|  |     55 | 
 | 
|  |     56 | // Tokens and Reverse Polish Notation
 | 
|  |     57 | abstract class Token
 | 
|  |     58 | case class T(n: Int) extends Token
 | 
|  |     59 | case object PL extends Token
 | 
|  |     60 | case object TI extends Token
 | 
|  |     61 | 
 | 
|  |     62 | // transfroming an Exp into a list of tokens
 | 
|  |     63 | def rp(e: Exp) : List[Token] = e match {
 | 
|  |     64 |   case N(n) => List(T(n))
 | 
|  |     65 |   case Plus(e1, e2) => rp(e1) ::: rp(e2) ::: List(PL) 
 | 
|  |     66 |   case Times(e1, e2) => rp(e1) ::: rp(e2) ::: List(TI) 
 | 
|  |     67 | }
 | 
|  |     68 | println(string(e2))
 | 
|  |     69 | println(rp(e2))
 | 
|  |     70 | 
 | 
|  |     71 | def comp(ls: List[Token], st: List[Int]) : Int = (ls, st) match {
 | 
|  |     72 |   case (Nil, st) => st.head 
 | 
|  |     73 |   case (T(n)::rest, st) => comp(rest, n::st)
 | 
|  |     74 |   case (PL::rest, n1::n2::st) => comp(rest, n1 + n2::st)
 | 
|  |     75 |   case (TI::rest, n1::n2::st) => comp(rest, n1 * n2::st)
 | 
|  |     76 | }
 | 
|  |     77 | 
 | 
|  |     78 | comp(rp(e), Nil)
 | 
|  |     79 | 
 | 
|  |     80 | def proc(s: String) : Token = s match {
 | 
|  |     81 |   case  "+" => PL
 | 
|  |     82 |   case  "*" => TI
 | 
|  |     83 |   case  _ => T(s.toInt) 
 | 
|  |     84 | }
 | 
|  |     85 | 
 | 
|  |     86 | comp("1 2 + 4 * 5 + 3 +".split(" ").toList.map(proc), Nil)
 | 
|  |     87 | 
 | 
|  |     88 | 
 | 
|  |     89 | 
 | 
|  |     90 | 
 | 
|  |     91 | // Sudoku 
 | 
|  |     92 | //========
 | 
|  |     93 | 
 | 
|  |     94 | // THE POINT OF THIS CODE IS NOT TO BE SUPER
 | 
|  |     95 | // EFFICIENT AND FAST, just explaining exhaustive
 | 
|  |     96 | // depth-first search
 | 
|  |     97 | 
 | 
|  |     98 | 
 | 
|  |     99 | val game0 = """.14.6.3..
 | 
|  |    100 |               |62...4..9
 | 
|  |    101 |               |.8..5.6..
 | 
|  |    102 |               |.6.2....3
 | 
|  |    103 |               |.7..1..5.
 | 
|  |    104 |               |5....9.6.
 | 
|  |    105 |               |..6.2..3.
 | 
|  |    106 |               |1..5...92
 | 
|  |    107 |               |..7.9.41.""".stripMargin.replaceAll("\\n", "")
 | 
|  |    108 | 
 | 
|  |    109 | type Pos = (Int, Int)
 | 
|  |    110 | val EmptyValue = '.'
 | 
|  |    111 | val MaxValue = 9
 | 
|  |    112 | 
 | 
|  |    113 | val allValues = "123456789".toList
 | 
|  |    114 | val indexes = (0 to 8).toList
 | 
|  |    115 | 
 | 
|  |    116 | 
 | 
|  |    117 | def empty(game: String) = game.indexOf(EmptyValue)
 | 
|  |    118 | def isDone(game: String) = empty(game) == -1 
 | 
|  |    119 | def emptyPosition(game: String) = 
 | 
|  |    120 |   (empty(game) % MaxValue, empty(game) / MaxValue)
 | 
|  |    121 | 
 | 
|  |    122 | 
 | 
|  |    123 | def get_row(game: String, y: Int) = 
 | 
|  |    124 |   indexes.map(col => game(y * MaxValue + col))
 | 
|  |    125 | def get_col(game: String, x: Int) = 
 | 
|  |    126 |   indexes.map(row => game(x + row * MaxValue))
 | 
|  |    127 | 
 | 
|  |    128 | def get_box(game: String, pos: Pos): List[Char] = {
 | 
|  |    129 |     def base(p: Int): Int = (p / 3) * 3
 | 
|  |    130 |     val x0 = base(pos._1)
 | 
|  |    131 |     val y0 = base(pos._2)
 | 
|  |    132 |     val ys = (y0 until y0 + 3).toList
 | 
|  |    133 |     (x0 until x0 + 3).toList.flatMap(x => ys.map(y => game(x + y * MaxValue)))
 | 
|  |    134 | }
 | 
|  |    135 | 
 | 
|  |    136 | //get_row(game0, 0)
 | 
|  |    137 | //get_row(game0, 1)
 | 
|  |    138 | //get_col(game0, 0)
 | 
|  |    139 | //get_box(game0, (3, 1))
 | 
|  |    140 | 
 | 
|  |    141 | 
 | 
|  |    142 | // this is not mutable!!
 | 
|  |    143 | def update(game: String, pos: Int, value: Char): String = 
 | 
|  |    144 |   game.updated(pos, value)
 | 
|  |    145 | 
 | 
|  |    146 | def toAvoid(game: String, pos: Pos): List[Char] = 
 | 
|  |    147 |   (get_col(game, pos._1) ++ get_row(game, pos._2) ++ get_box(game, pos))
 | 
|  |    148 | 
 | 
|  |    149 | def candidates(game: String, pos: Pos): List[Char] = 
 | 
|  |    150 |   allValues.diff(toAvoid(game, pos))
 | 
|  |    151 | 
 | 
|  |    152 | //candidates(game0, (0,0))
 | 
|  |    153 | 
 | 
|  |    154 | def pretty(game: String): String = 
 | 
|  |    155 |   "\n" + (game.sliding(MaxValue, MaxValue).mkString("\n"))
 | 
|  |    156 | 
 | 
|  |    157 | 
 | 
|  |    158 | def search(game: String): List[String] = {
 | 
|  |    159 |   if (isDone(game)) List(game)
 | 
|  |    160 |   else {
 | 
|  |    161 |     val cs = candidates(game, emptyPosition(game))
 | 
|  |    162 |     cs.map(c => search(update(game, empty(game), c))).toList.flatten
 | 
|  |    163 |   }
 | 
|  |    164 | }
 | 
|  |    165 | 
 | 
|  |    166 | search(game0).map(pretty)
 | 
|  |    167 | 
 | 
|  |    168 | val game1 = """23.915...
 | 
|  |    169 |               |...2..54.
 | 
|  |    170 |               |6.7......
 | 
|  |    171 |               |..1.....9
 | 
|  |    172 |               |89.5.3.17
 | 
|  |    173 |               |5.....6..
 | 
|  |    174 |               |......9.5
 | 
|  |    175 |               |.16..7...
 | 
|  |    176 |               |...329..1""".stripMargin.replaceAll("\\n", "")
 | 
|  |    177 | 
 | 
|  |    178 | search(game1).map(pretty)
 | 
|  |    179 | 
 | 
|  |    180 | // a game that is in the hard category
 | 
|  |    181 | val game2 = """8........
 | 
|  |    182 |               |..36.....
 | 
|  |    183 |               |.7..9.2..
 | 
|  |    184 |               |.5...7...
 | 
|  |    185 |               |....457..
 | 
|  |    186 |               |...1...3.
 | 
|  |    187 |               |..1....68
 | 
|  |    188 |               |..85...1.
 | 
|  |    189 |               |.9....4..""".stripMargin.replaceAll("\\n", "")
 | 
|  |    190 | 
 | 
|  |    191 | search(game2).map(pretty)
 | 
|  |    192 | 
 | 
|  |    193 | // game with multiple solutions
 | 
|  |    194 | val game3 = """.8...9743
 | 
|  |    195 |               |.5...8.1.
 | 
|  |    196 |               |.1.......
 | 
|  |    197 |               |8....5...
 | 
|  |    198 |               |...8.4...
 | 
|  |    199 |               |...3....6
 | 
|  |    200 |               |.......7.
 | 
|  |    201 |               |.3.5...8.
 | 
|  |    202 |               |9724...5.""".stripMargin.replaceAll("\\n", "")
 | 
|  |    203 | 
 | 
|  |    204 | search(game3).map(pretty).foreach(println)
 | 
|  |    205 | 
 | 
|  |    206 | // for measuring time
 | 
|  |    207 | def time_needed[T](i: Int, code: => T) = {
 | 
|  |    208 |   val start = System.nanoTime()
 | 
|  |    209 |   for (j <- 1 to i) code
 | 
|  |    210 |   val end = System.nanoTime()
 | 
|  |    211 |   s"${(end - start) / 1.0e9} secs"
 | 
|  |    212 | }
 | 
|  |    213 | 
 | 
|  |    214 | time_needed(1, search(game2))
 | 
|  |    215 | 
 | 
|  |    216 | 
 | 
|  |    217 | 
 | 
|  |    218 | // Tail recursion
 | 
|  |    219 | //================
 | 
|  |    220 | 
 | 
|  |    221 | 
 | 
|  |    222 | def fact(n: Long): Long = 
 | 
|  |    223 |   if (n == 0) 1 else n * fact(n - 1)
 | 
|  |    224 | 
 | 
|  |    225 | 
 | 
|  |    226 | fact(10)              // ok
 | 
|  |    227 | fact(1000)            // silly
 | 
|  |    228 | fact(10000)           // produces a stackoverflow
 | 
|  |    229 | 
 | 
|  |    230 | def factB(n: BigInt): BigInt = 
 | 
|  |    231 |   if (n == 0) 1 else n * factB(n - 1)
 | 
|  |    232 | 
 | 
|  |    233 | factB(1000)
 | 
|  |    234 | 
 | 
|  |    235 | 
 | 
|  |    236 | def factT(n: BigInt, acc: BigInt): BigInt =
 | 
|  |    237 |   if (n == 0) acc else factT(n - 1, n * acc)
 | 
|  |    238 | 
 | 
|  |    239 | factT(10, 1)
 | 
|  |    240 | println(factT(100000, 1))
 | 
|  |    241 | 
 | 
|  |    242 | // there is a flag for ensuring a function is tail recursive
 | 
|  |    243 | import scala.annotation.tailrec
 | 
|  |    244 | 
 | 
|  |    245 | @tailrec
 | 
|  |    246 | def factT(n: BigInt, acc: BigInt): BigInt =
 | 
|  |    247 |   if (n == 0) acc else factT(n - 1, n * acc)
 | 
|  |    248 | 
 | 
|  |    249 | factT(100000, 1)
 | 
|  |    250 | 
 | 
|  |    251 | // for tail-recursive functions the Scala compiler
 | 
|  |    252 | // generates loop-like code, which does not need
 | 
|  |    253 | // to allocate stack-space in each recursive
 | 
|  |    254 | // call; Scala can do this only for tail-recursive
 | 
|  |    255 | // functions
 | 
|  |    256 | 
 | 
|  |    257 | // tail recursive version that searches 
 | 
|  |    258 | // for all Sudoku solutions
 | 
|  |    259 | 
 | 
|  |    260 | 
 | 
|  |    261 | def searchT(games: List[String], sols: List[String]): List[String] = games match {
 | 
|  |    262 |   case Nil => sols
 | 
|  |    263 |   case game::rest => {
 | 
|  |    264 |     if (isDone(game)) searchT(rest, game::sols)
 | 
|  |    265 |     else {
 | 
|  |    266 |       val cs = candidates(game, emptyPosition(game))
 | 
|  |    267 |       searchT(cs.map(c => update(game, empty(game), c)) ::: rest, sols)
 | 
|  |    268 |     }
 | 
|  |    269 |   }
 | 
|  |    270 | }
 | 
|  |    271 | 
 | 
|  |    272 | searchT(List(game3), List()).map(pretty)
 | 
|  |    273 | 
 | 
|  |    274 | 
 | 
|  |    275 | // tail recursive version that searches 
 | 
|  |    276 | // for a single solution
 | 
|  |    277 | 
 | 
|  |    278 | def search1T(games: List[String]): Option[String] = games match {
 | 
|  |    279 |   case Nil => None
 | 
|  |    280 |   case game::rest => {
 | 
|  |    281 |     if (isDone(game)) Some(game)
 | 
|  |    282 |     else {
 | 
|  |    283 |       val cs = candidates(game, emptyPosition(game))
 | 
|  |    284 |       search1T(cs.map(c => update(game, empty(game), c)) ::: rest)
 | 
|  |    285 |     }
 | 
|  |    286 |   }
 | 
|  |    287 | }
 | 
|  |    288 | 
 | 
|  |    289 | search1T(List(game3)).map(pretty)
 | 
|  |    290 | time_needed(1, search1T(List(game3)))
 | 
|  |    291 | time_needed(1, search1T(List(game2)))
 | 
|  |    292 | 
 | 
|  |    293 | // game with multiple solutions
 | 
|  |    294 | val game3 = """.8...9743
 | 
|  |    295 |               |.5...8.1.
 | 
|  |    296 |               |.1.......
 | 
|  |    297 |               |8....5...
 | 
|  |    298 |               |...8.4...
 | 
|  |    299 |               |...3....6
 | 
|  |    300 |               |.......7.
 | 
|  |    301 |               |.3.5...8.
 | 
|  |    302 |               |9724...5.""".stripMargin.replaceAll("\\n", "")
 | 
|  |    303 | 
 | 
|  |    304 | searchT(List(game3), Nil).map(pretty)
 | 
|  |    305 | search1T(List(game3)).map(pretty)
 | 
|  |    306 | 
 | 
|  |    307 | // Moral: Whenever a recursive function is resource-critical
 | 
|  |    308 | // (i.e. works with large recursion depth), then you need to
 | 
|  |    309 | // write it in tail-recursive fashion.
 | 
|  |    310 | // 
 | 
|  |    311 | // Unfortuantely, Scala because of current limitations in 
 | 
|  |    312 | // the JVM is not as clever as other functional languages. It can 
 | 
|  |    313 | // only optimise "self-tail calls". This excludes the cases of 
 | 
|  |    314 | // multiple functions making tail calls to each other. Well,
 | 
|  |    315 | // nothing is perfect. 
 | 
|  |    316 | 
 | 
|  |    317 | 
 | 
|  |    318 | 
 | 
|  |    319 | 
 | 
| 222 |    320 | // Polymorphic Types
 | 
|  |    321 | //===================
 | 
|  |    322 | 
 | 
|  |    323 | // You do not want to write functions like contains, first, 
 | 
|  |    324 | // length and so on for every type of lists.
 | 
|  |    325 | 
 | 
| 224 |    326 | 
 | 
| 222 |    327 | def length_string_list(lst: List[String]): Int = lst match {
 | 
|  |    328 |   case Nil => 0
 | 
|  |    329 |   case x::xs => 1 + length_string_list(xs)
 | 
|  |    330 | }
 | 
|  |    331 | 
 | 
|  |    332 | def length_int_list(lst: List[Int]): Int = lst match {
 | 
|  |    333 |   case Nil => 0
 | 
|  |    334 |   case x::xs => 1 + length_int_list(xs)
 | 
|  |    335 | }
 | 
|  |    336 | 
 | 
|  |    337 | length_string_list(List("1", "2", "3", "4"))
 | 
|  |    338 | length_int_list(List(1, 2, 3, 4))
 | 
|  |    339 | 
 | 
|  |    340 | def length[A](lst: List[A]): Int = lst match {
 | 
|  |    341 |   case Nil => 0
 | 
|  |    342 |   case x::xs => 1 + length(xs)
 | 
|  |    343 | }
 | 
|  |    344 | length(List("1", "2", "3", "4"))
 | 
|  |    345 | length(List(1, 2, 3, 4))
 | 
|  |    346 | 
 | 
|  |    347 | 
 | 
|  |    348 | def map[A, B](lst: List[A], f: A => B): List[B] = lst match {
 | 
|  |    349 |   case Nil => Nil
 | 
|  |    350 |   case x::xs => f(x)::map(xs, f) 
 | 
|  |    351 | }
 | 
|  |    352 | 
 | 
| 226 |    353 | map(List(1, 2, 3, 4), (x: Int) => x.toString)
 | 
| 222 |    354 | 
 | 
|  |    355 | 
 | 
|  |    356 | 
 | 
|  |    357 | // distinct / distinctBy
 | 
|  |    358 | 
 | 
|  |    359 | val ls = List(1,2,3,3,2,4,3,2,1)
 | 
|  |    360 | ls.distinct
 | 
|  |    361 | 
 | 
| 226 |    362 | ls.minBy(_._2)
 | 
|  |    363 | ls.sortBy(_._1)
 | 
| 222 |    364 | 
 | 
| 223 |    365 | def distinctBy[B, C](xs: List[B], 
 | 
|  |    366 |                      f: B => C, 
 | 
|  |    367 |                      acc: List[C] = Nil): List[B] = xs match {
 | 
| 218 |    368 |   case Nil => Nil
 | 
| 223 |    369 |   case x::xs => {
 | 
| 218 |    370 |     val res = f(x)
 | 
|  |    371 |     if (acc.contains(res)) distinctBy(xs, f, acc)  
 | 
|  |    372 |     else x::distinctBy(xs, f, res::acc)
 | 
|  |    373 |   }
 | 
|  |    374 | } 
 | 
|  |    375 | 
 | 
| 223 |    376 | // distinctBy  with the identity function is 
 | 
|  |    377 | // just distinct
 | 
| 222 |    378 | distinctBy(ls, (x: Int) => x)
 | 
|  |    379 | 
 | 
|  |    380 | 
 | 
|  |    381 | val cs = List('A', 'b', 'a', 'c', 'B', 'D', 'd')
 | 
|  |    382 | 
 | 
|  |    383 | distinctBy(cs, (c:Char) => c.toUpper)
 | 
|  |    384 | 
 | 
|  |    385 | 
 | 
|  |    386 | 
 | 
|  |    387 | // Type inference is local in Scala
 | 
|  |    388 | 
 | 
|  |    389 | def id[T](x: T) : T = x
 | 
|  |    390 | 
 | 
|  |    391 | val x = id(322)          // Int
 | 
|  |    392 | val y = id("hey")        // String
 | 
| 226 |    393 | val z = id(Set[Int](1,2,3,4)) // Set[Int]
 | 
| 222 |    394 | 
 | 
|  |    395 | 
 | 
|  |    396 | 
 | 
|  |    397 | // The type variable concept in Scala can get really complicated.
 | 
|  |    398 | //
 | 
|  |    399 | // - variance (OO)
 | 
|  |    400 | // - bounds (subtyping)
 | 
|  |    401 | // - quantification
 | 
|  |    402 | 
 | 
|  |    403 | // Java has issues with this too: Java allows
 | 
| 223 |    404 | // to write the following incorrect code, and
 | 
|  |    405 | // only recovers by raising an exception
 | 
|  |    406 | // at runtime.
 | 
| 222 |    407 | 
 | 
| 223 |    408 | // Object[] arr = new Integer[10];
 | 
|  |    409 | // arr[0] = "Hello World";
 | 
| 222 |    410 | 
 | 
|  |    411 | 
 | 
| 226 |    412 | // Scala gives you a compile-time error, which
 | 
|  |    413 | // is much better.
 | 
| 222 |    414 | 
 | 
|  |    415 | var arr = Array[Int]()
 | 
|  |    416 | arr(0) = "Hello World"
 | 
|  |    417 | 
 | 
|  |    418 | 
 | 
|  |    419 | 
 | 
|  |    420 | 
 | 
| 325 |    421 | // Cool Stuff in Scala
 | 
|  |    422 | //=====================
 | 
|  |    423 | 
 | 
|  |    424 | 
 | 
|  |    425 | // Implicits or How to Pimp your Library
 | 
|  |    426 | //======================================
 | 
|  |    427 | //
 | 
|  |    428 | // For example adding your own methods to Strings:
 | 
|  |    429 | // Imagine you want to increment strings, like
 | 
|  |    430 | //
 | 
|  |    431 | //     "HAL".increment
 | 
|  |    432 | //
 | 
|  |    433 | // you can avoid ugly fudges, like a MyString, by
 | 
|  |    434 | // using implicit conversions.
 | 
|  |    435 | 
 | 
|  |    436 | 
 | 
|  |    437 | implicit class MyString(s: String) {
 | 
|  |    438 |   def increment = s.map(c => (c + 1).toChar) 
 | 
|  |    439 | }
 | 
|  |    440 | 
 | 
|  |    441 | "HAL".increment
 | 
|  |    442 | 
 | 
|  |    443 | 
 | 
|  |    444 | // Abstract idea:
 | 
|  |    445 | // In that version implicit conversions were used to solve the 
 | 
|  |    446 | // late extension problem; namely, given a class C and a class T, 
 | 
|  |    447 | // how to have C extend T without touching or recompiling C. 
 | 
|  |    448 | // Conversions add a wrapper when a member of T is requested 
 | 
|  |    449 | // from an instance of C.
 | 
|  |    450 | 
 | 
|  |    451 | //Another example (TimeUnit in 2.13?)
 | 
|  |    452 | 
 | 
|  |    453 | import scala.concurrent.duration.{TimeUnit,SECONDS,MINUTES}
 | 
|  |    454 | 
 | 
|  |    455 | case class Duration(time: Long, unit: TimeUnit) {
 | 
|  |    456 |   def +(o: Duration) = 
 | 
|  |    457 |     Duration(time + unit.convert(o.time, o.unit), unit)
 | 
|  |    458 | }
 | 
|  |    459 | 
 | 
|  |    460 | implicit class Int2Duration(that: Int) {
 | 
|  |    461 |   def seconds = new Duration(that, SECONDS)
 | 
|  |    462 |   def minutes = new Duration(that, MINUTES)
 | 
|  |    463 | }
 | 
|  |    464 | 
 | 
|  |    465 | 5.seconds + 2.minutes   //Duration(125L, SECONDS )
 | 
|  |    466 | 2.minutes + 60.seconds
 | 
|  |    467 | 
 | 
|  |    468 | 
 | 
|  |    469 | 
 | 
|  |    470 | 
 | 
|  |    471 | // Regular expressions - the power of DSLs in Scala
 | 
|  |    472 | //==================================================
 | 
|  |    473 | 
 | 
|  |    474 | abstract class Rexp
 | 
|  |    475 | case object ZERO extends Rexp                     // nothing
 | 
|  |    476 | case object ONE extends Rexp                      // the empty string
 | 
|  |    477 | case class CHAR(c: Char) extends Rexp             // a character c
 | 
|  |    478 | case class ALT(r1: Rexp, r2: Rexp) extends Rexp   // alternative  r1 + r2
 | 
|  |    479 | case class SEQ(r1: Rexp, r2: Rexp) extends Rexp   // sequence     r1 . r2  
 | 
|  |    480 | case class STAR(r: Rexp) extends Rexp             // star         r*
 | 
|  |    481 | 
 | 
|  |    482 | 
 | 
|  |    483 | 
 | 
|  |    484 | // writing (ab)* in the format above is 
 | 
|  |    485 | // tedious
 | 
|  |    486 | val r0 = STAR(SEQ(CHAR('a'), CHAR('b')))
 | 
|  |    487 | 
 | 
|  |    488 | 
 | 
|  |    489 | // some convenience for typing in regular expressions
 | 
|  |    490 | import scala.language.implicitConversions    
 | 
|  |    491 | import scala.language.reflectiveCalls 
 | 
|  |    492 | 
 | 
|  |    493 | def charlist2rexp(s: List[Char]): Rexp = s match {
 | 
|  |    494 |   case Nil => ONE
 | 
|  |    495 |   case c::Nil => CHAR(c)
 | 
|  |    496 |   case c::s => SEQ(CHAR(c), charlist2rexp(s))
 | 
|  |    497 | }
 | 
|  |    498 | implicit def string2rexp(s: String): Rexp = 
 | 
|  |    499 |   charlist2rexp(s.toList)
 | 
|  |    500 | 
 | 
|  |    501 | 
 | 
|  |    502 | val r1 = STAR("ab")
 | 
|  |    503 | val r2 = STAR(ALT("ab", "baa baa black sheep"))
 | 
|  |    504 | val r3 = STAR(SEQ("ab", ALT("a", "b")))
 | 
|  |    505 | 
 | 
|  |    506 | implicit def RexpOps (r: Rexp) = new {
 | 
|  |    507 |   def | (s: Rexp) = ALT(r, s)
 | 
|  |    508 |   def % = STAR(r)
 | 
|  |    509 |   def ~ (s: Rexp) = SEQ(r, s)
 | 
|  |    510 | }
 | 
|  |    511 | 
 | 
|  |    512 | implicit def stringOps (s: String) = new {
 | 
|  |    513 |   def | (r: Rexp) = ALT(s, r)
 | 
|  |    514 |   def | (r: String) = ALT(s, r)
 | 
|  |    515 |   def % = STAR(s)
 | 
|  |    516 |   def ~ (r: Rexp) = SEQ(s, r)
 | 
|  |    517 |   def ~ (r: String) = SEQ(s, r)
 | 
|  |    518 | }
 | 
|  |    519 | 
 | 
|  |    520 | //example regular expressions
 | 
|  |    521 | val digit = "0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9"
 | 
|  |    522 | val sign = "+" | "-" | ""
 | 
|  |    523 | val number = sign ~ digit ~ digit.% 
 | 
|  |    524 | 
 | 
|  |    525 | 
 | 
| 222 |    526 | //
 | 
|  |    527 | // Object Oriented Programming in Scala
 | 
|  |    528 | //
 | 
|  |    529 | // =====================================
 | 
|  |    530 | 
 | 
|  |    531 | abstract class Animal
 | 
| 226 |    532 | case class Bird(name: String) extends Animal {
 | 
|  |    533 |    override def toString = name
 | 
|  |    534 | }
 | 
| 222 |    535 | case class Mammal(name: String) extends Animal
 | 
|  |    536 | case class Reptile(name: String) extends Animal
 | 
|  |    537 | 
 | 
| 226 |    538 | Bird("Sparrow")
 | 
|  |    539 | 
 | 
| 223 |    540 | println(Bird("Sparrow"))
 | 
| 222 |    541 | println(Bird("Sparrow").toString)
 | 
|  |    542 | 
 | 
|  |    543 | 
 | 
|  |    544 | // you can override methods
 | 
|  |    545 | case class Bird(name: String) extends Animal {
 | 
|  |    546 |   override def toString = name
 | 
|  |    547 | }
 | 
|  |    548 | 
 | 
|  |    549 | 
 | 
|  |    550 | // There is a very convenient short-hand notation
 | 
| 226 |    551 | // for constructors:
 | 
| 222 |    552 | 
 | 
|  |    553 | class Fraction(x: Int, y: Int) {
 | 
|  |    554 |   def numer = x
 | 
|  |    555 |   def denom = y
 | 
|  |    556 | }
 | 
|  |    557 | 
 | 
|  |    558 | 
 | 
|  |    559 | case class Fraction(numer: Int, denom: Int)
 | 
|  |    560 | 
 | 
|  |    561 | val half = Fraction(1, 2)
 | 
|  |    562 | 
 | 
|  |    563 | half.denom
 | 
|  |    564 | 
 | 
|  |    565 | 
 | 
| 223 |    566 | // In mandelbrot.scala I used complex (imaginary) numbers 
 | 
|  |    567 | // and implemented the usual arithmetic operations for complex 
 | 
|  |    568 | // numbers.
 | 
| 222 |    569 | 
 | 
|  |    570 | case class Complex(re: Double, im: Double) { 
 | 
|  |    571 |   // represents the complex number re + im * i
 | 
|  |    572 |   def +(that: Complex) = Complex(this.re + that.re, this.im + that.im)
 | 
|  |    573 |   def -(that: Complex) = Complex(this.re - that.re, this.im - that.im)
 | 
|  |    574 |   def *(that: Complex) = Complex(this.re * that.re - this.im * that.im,
 | 
|  |    575 |                                  this.re * that.im + that.re * this.im)
 | 
|  |    576 |   def *(that: Double) = Complex(this.re * that, this.im * that)
 | 
|  |    577 |   def abs = Math.sqrt(this.re * this.re + this.im * this.im)
 | 
|  |    578 | }
 | 
|  |    579 | 
 | 
|  |    580 | val test = Complex(1, 2) + Complex (3, 4)
 | 
|  |    581 | 
 | 
|  |    582 | // this could have equally been written as
 | 
|  |    583 | val test = Complex(1, 2).+(Complex (3, 4))
 | 
|  |    584 | 
 | 
|  |    585 | // this applies to all methods, but requires
 | 
|  |    586 | import scala.language.postfixOps
 | 
|  |    587 | 
 | 
|  |    588 | List(5, 2, 3, 4).sorted
 | 
|  |    589 | List(5, 2, 3, 4) sorted
 | 
|  |    590 | 
 | 
|  |    591 | 
 | 
| 223 |    592 | // ...to allow the notation n + m * i
 | 
| 222 |    593 | import scala.language.implicitConversions   
 | 
| 223 |    594 | 
 | 
| 226 |    595 | val i = Complex(0, 1)
 | 
| 222 |    596 | implicit def double2complex(re: Double) = Complex(re, 0)
 | 
|  |    597 | 
 | 
|  |    598 | 
 | 
|  |    599 | val inum1 = -2.0 + -1.5 * i
 | 
|  |    600 | val inum2 =  1.0 +  1.5 * i
 | 
|  |    601 | 
 | 
|  |    602 | 
 | 
|  |    603 | 
 | 
| 223 |    604 | // All is public by default....so no public is needed.
 | 
|  |    605 | // You can have the usual restrictions about private 
 | 
|  |    606 | // values and methods, if you are MUTABLE !!!
 | 
| 222 |    607 | 
 | 
|  |    608 | case class BankAccount(init: Int) {
 | 
|  |    609 | 
 | 
|  |    610 |   private var balance = init
 | 
|  |    611 | 
 | 
|  |    612 |   def deposit(amount: Int): Unit = {
 | 
|  |    613 |     if (amount > 0) balance = balance + amount
 | 
|  |    614 |   }
 | 
|  |    615 | 
 | 
|  |    616 |   def withdraw(amount: Int): Int =
 | 
|  |    617 |     if (0 < amount && amount <= balance) {
 | 
|  |    618 |       balance = balance - amount
 | 
|  |    619 |       balance
 | 
|  |    620 |     } else throw new Error("insufficient funds")
 | 
|  |    621 | }
 | 
|  |    622 | 
 | 
| 223 |    623 | // BUT since we are completely IMMUTABLE, this is 
 | 
|  |    624 | // virtually of not concern to us.
 | 
| 222 |    625 | 
 | 
|  |    626 | 
 | 
|  |    627 | 
 | 
| 243 |    628 | // another example about Fractions
 | 
|  |    629 | import scala.language.implicitConversions
 | 
|  |    630 | import scala.language.reflectiveCalls
 | 
|  |    631 | 
 | 
|  |    632 | 
 | 
|  |    633 | case class Fraction(numer: Int, denom: Int) {
 | 
|  |    634 |   override def toString = numer.toString + "/" + denom.toString
 | 
|  |    635 | 
 | 
|  |    636 |   def +(other: Fraction) = Fraction(numer + other.numer, denom + other.denom)
 | 
|  |    637 |   def /(other: Fraction) = Fraction(numer * other.denom, denom * other.numer)
 | 
|  |    638 |   def /% (other: Fraction) = Fraction(numer * other.denom, denom * other.numer)
 | 
|  |    639 | 
 | 
|  |    640 | }
 | 
|  |    641 | 
 | 
|  |    642 | implicit def Int2Fraction(x: Int) = Fraction(x, 1)
 | 
|  |    643 | 
 | 
|  |    644 | 
 | 
|  |    645 | val half = Fraction(1, 2)
 | 
|  |    646 | val third = Fraction (1, 3)
 | 
|  |    647 | 
 | 
|  |    648 | half + third
 | 
|  |    649 | half / third
 | 
|  |    650 | 
 | 
|  |    651 | // not sure if one can get this to work
 | 
|  |    652 | // properly, since Scala just cannot find out
 | 
|  |    653 | // if / is for ints or for Fractions 
 | 
|  |    654 | (1 / 3) + half
 | 
|  |    655 | (1 / 2) + third
 | 
|  |    656 | 
 | 
|  |    657 | // either you have to force the Fraction-type by
 | 
|  |    658 | // using a method that is not defined for ints
 | 
|  |    659 | (1 /% 3) + half
 | 
|  |    660 | (1 /% 2) + third
 | 
|  |    661 | 
 | 
|  |    662 | 
 | 
|  |    663 | // ...or explicitly give the type in order to allow
 | 
|  |    664 | // Scala to do the conversion to Fractions 
 | 
|  |    665 | ((1:Fraction) / 3) + half
 | 
|  |    666 | (1 / (3: Fraction)) + half
 | 
|  |    667 | 
 | 
| 222 |    668 | 
 | 
|  |    669 | 
 | 
|  |    670 | // DFAs in Scala  
 | 
| 226 |    671 | //===============
 | 
| 222 |    672 | import scala.util.Try
 | 
| 218 |    673 | 
 | 
|  |    674 | 
 | 
| 222 |    675 | // A is the state type
 | 
|  |    676 | // C is the input (usually characters)
 | 
|  |    677 | 
 | 
| 223 |    678 | case class DFA[A, C](start: A,              // starting state
 | 
|  |    679 |                      delta: (A, C) => A,    // transition function
 | 
|  |    680 |                      fins:  A => Boolean) { // final states (Set)
 | 
| 222 |    681 | 
 | 
|  |    682 |   def deltas(q: A, s: List[C]) : A = s match {
 | 
|  |    683 |     case Nil => q
 | 
|  |    684 |     case c::cs => deltas(delta(q, c), cs)
 | 
|  |    685 |   }
 | 
|  |    686 | 
 | 
|  |    687 |   def accepts(s: List[C]) : Boolean = 
 | 
|  |    688 |     Try(fins(deltas(start, s))) getOrElse false
 | 
|  |    689 | }
 | 
|  |    690 | 
 | 
|  |    691 | // the example shown in the handout 
 | 
|  |    692 | abstract class State
 | 
|  |    693 | case object Q0 extends State
 | 
|  |    694 | case object Q1 extends State
 | 
|  |    695 | case object Q2 extends State
 | 
|  |    696 | case object Q3 extends State
 | 
|  |    697 | case object Q4 extends State
 | 
|  |    698 | 
 | 
|  |    699 | val delta : (State, Char) => State = 
 | 
|  |    700 |   { case (Q0, 'a') => Q1
 | 
|  |    701 |     case (Q0, 'b') => Q2
 | 
|  |    702 |     case (Q1, 'a') => Q4
 | 
|  |    703 |     case (Q1, 'b') => Q2
 | 
|  |    704 |     case (Q2, 'a') => Q3
 | 
|  |    705 |     case (Q2, 'b') => Q2
 | 
|  |    706 |     case (Q3, 'a') => Q4
 | 
|  |    707 |     case (Q3, 'b') => Q0
 | 
|  |    708 |     case (Q4, 'a') => Q4
 | 
|  |    709 |     case (Q4, 'b') => Q4 
 | 
|  |    710 |     case _ => throw new Exception("Undefined") }
 | 
|  |    711 | 
 | 
|  |    712 | val dfa = DFA(Q0, delta, Set[State](Q4))
 | 
|  |    713 | 
 | 
|  |    714 | dfa.accepts("abaaa".toList)     // true
 | 
|  |    715 | dfa.accepts("bbabaab".toList)   // true
 | 
|  |    716 | dfa.accepts("baba".toList)      // false
 | 
|  |    717 | dfa.accepts("abc".toList)       // false
 | 
|  |    718 | 
 | 
| 223 |    719 | // another DFA with a Sink state
 | 
| 222 |    720 | abstract class S
 | 
|  |    721 | case object S0 extends S
 | 
|  |    722 | case object S1 extends S
 | 
|  |    723 | case object S2 extends S
 | 
|  |    724 | case object Sink extends S
 | 
|  |    725 | 
 | 
|  |    726 | // transition function with a sink state
 | 
| 223 |    727 | val sigma : (S, Char) => S = 
 | 
| 222 |    728 |   { case (S0, 'a') => S1
 | 
|  |    729 |     case (S1, 'a') => S2
 | 
|  |    730 |     case _ => Sink
 | 
|  |    731 |   }
 | 
|  |    732 | 
 | 
|  |    733 | val dfa2 = DFA(S0, sigma, Set[S](S2))
 | 
|  |    734 | 
 | 
|  |    735 | dfa2.accepts("aa".toList)        // true
 | 
|  |    736 | dfa2.accepts("".toList)          // false
 | 
|  |    737 | dfa2.accepts("ab".toList)        // false
 | 
|  |    738 | 
 | 
| 223 |    739 | //  we could also have a dfa for numbers
 | 
|  |    740 | val sigmai : (S, Int) => S = 
 | 
|  |    741 |   { case (S0, 1) => S1
 | 
|  |    742 |     case (S1, 1) => S2
 | 
|  |    743 |     case _ => Sink
 | 
|  |    744 |   }
 | 
|  |    745 | 
 | 
|  |    746 | val dfa3 = DFA(S0, sigmai, Set[S](S2))
 | 
|  |    747 | 
 | 
|  |    748 | dfa3.accepts(List(1, 1))        // true
 | 
|  |    749 | dfa3.accepts(Nil)               // false
 | 
|  |    750 | dfa3.accepts(List(1, 2))        // false
 | 
|  |    751 | 
 | 
| 222 |    752 | 
 | 
|  |    753 | 
 | 
|  |    754 | 
 | 
|  |    755 | // NFAs (Nondeterministic Finite Automata)
 | 
|  |    756 | 
 | 
|  |    757 | 
 | 
| 223 |    758 | case class NFA[A, C](starts: Set[A],          // starting states
 | 
|  |    759 |                      delta: (A, C) => Set[A], // transition function
 | 
|  |    760 |                      fins:  A => Boolean) {   // final states 
 | 
| 222 |    761 | 
 | 
|  |    762 |   // given a state and a character, what is the set of 
 | 
|  |    763 |   // next states? if there is none => empty set
 | 
|  |    764 |   def next(q: A, c: C) : Set[A] = 
 | 
|  |    765 |     Try(delta(q, c)) getOrElse Set[A]() 
 | 
|  |    766 | 
 | 
| 242 |    767 |   def nexts(qs: Set[A], c: C) : Set[A] =
 | 
|  |    768 |     qs.flatMap(next(_, c))
 | 
|  |    769 | 
 | 
| 222 |    770 |   // depth-first version of accepts
 | 
|  |    771 |   def search(q: A, s: List[C]) : Boolean = s match {
 | 
|  |    772 |     case Nil => fins(q)
 | 
|  |    773 |     case c::cs => next(q, c).exists(search(_, cs))
 | 
|  |    774 |   }
 | 
|  |    775 | 
 | 
|  |    776 |   def accepts(s: List[C]) : Boolean =
 | 
|  |    777 |     starts.exists(search(_, s))
 | 
|  |    778 | }
 | 
|  |    779 | 
 | 
|  |    780 | 
 | 
|  |    781 | 
 | 
|  |    782 | // NFA examples
 | 
|  |    783 | 
 | 
|  |    784 | val nfa_trans1 : (State, Char) => Set[State] = 
 | 
|  |    785 |   { case (Q0, 'a') => Set(Q0, Q1) 
 | 
|  |    786 |     case (Q0, 'b') => Set(Q2) 
 | 
|  |    787 |     case (Q1, 'a') => Set(Q1) 
 | 
|  |    788 |     case (Q2, 'b') => Set(Q2) }
 | 
|  |    789 | 
 | 
|  |    790 | val nfa = NFA(Set[State](Q0), nfa_trans1, Set[State](Q2))
 | 
|  |    791 | 
 | 
|  |    792 | nfa.accepts("aa".toList)             // false
 | 
|  |    793 | nfa.accepts("aaaaa".toList)          // false
 | 
|  |    794 | nfa.accepts("aaaaab".toList)         // true
 | 
|  |    795 | nfa.accepts("aaaaabbb".toList)       // true
 | 
|  |    796 | nfa.accepts("aaaaabbbaaa".toList)    // false
 | 
|  |    797 | nfa.accepts("ac".toList)             // false
 | 
|  |    798 | 
 | 
|  |    799 | 
 | 
| 223 |    800 | // Q: Why the kerfuffle about the polymorphic types in DFAs/NFAs?
 | 
| 226 |    801 | // A: Subset construction. Here the state type for the DFA is
 | 
|  |    802 | //    sets of states.
 | 
| 222 |    803 | 
 | 
|  |    804 | def subset[A, C](nfa: NFA[A, C]) : DFA[Set[A], C] = {
 | 
|  |    805 |   DFA(nfa.starts, 
 | 
|  |    806 |       { case (qs, c) => nfa.nexts(qs, c) }, 
 | 
|  |    807 |       _.exists(nfa.fins))
 | 
|  |    808 | }
 | 
|  |    809 | 
 | 
|  |    810 | subset(nfa1).accepts("aa".toList)             // false
 | 
|  |    811 | subset(nfa1).accepts("aaaaa".toList)          // false
 | 
|  |    812 | subset(nfa1).accepts("aaaaab".toList)         // true
 | 
|  |    813 | subset(nfa1).accepts("aaaaabbb".toList)       // true
 | 
|  |    814 | subset(nfa1).accepts("aaaaabbbaaa".toList)    // false
 | 
|  |    815 | subset(nfa1).accepts("ac".toList)             // false
 | 
|  |    816 | 
 | 
|  |    817 | 
 | 
|  |    818 | 
 | 
|  |    819 | 
 | 
|  |    820 | 
 | 
|  |    821 | 
 | 
|  |    822 | 
 | 
|  |    823 | 
 | 
|  |    824 | // Lazy Evaluation
 | 
|  |    825 | //=================
 | 
|  |    826 | //
 | 
| 226 |    827 | // Do not evaluate arguments just yet:
 | 
|  |    828 | // this uses the => in front of the type
 | 
|  |    829 | // of the code-argument
 | 
| 222 |    830 | 
 | 
|  |    831 | def time_needed[T](i: Int, code: => T) = {
 | 
|  |    832 |   val start = System.nanoTime()
 | 
|  |    833 |   for (j <- 1 to i) code
 | 
|  |    834 |   val end = System.nanoTime()
 | 
|  |    835 |   (end - start)/(i * 1.0e9)
 | 
|  |    836 | }
 | 
|  |    837 | 
 | 
| 325 |    838 | 
 | 
|  |    839 | // Mind-Blowing Regular Expressions
 | 
|  |    840 | 
 | 
| 222 |    841 | // same examples using the internal regexes
 | 
|  |    842 | val evil = "(a*)*b"
 | 
|  |    843 | 
 | 
| 325 |    844 | 
 | 
|  |    845 | println("a" * 100)
 | 
|  |    846 | 
 | 
| 222 |    847 | ("a" * 10 ++ "b").matches(evil)
 | 
|  |    848 | ("a" * 10).matches(evil)
 | 
|  |    849 | ("a" * 10000).matches(evil)
 | 
|  |    850 | ("a" * 20000).matches(evil)
 | 
| 226 |    851 | ("a" * 50000).matches(evil)
 | 
| 222 |    852 | 
 | 
| 325 |    853 | time_needed(1, ("a" * 10000).matches(evil))
 |