progs/lecture4.scala
changeset 326 e5453add7df6
parent 325 ca9c1cf929fa
child 380 d19b0a50ceb9
equal deleted inserted replaced
325:ca9c1cf929fa 326:e5453add7df6
    28 
    28 
    29 // simplification rules:
    29 // simplification rules:
    30 // e + 0, 0 + e => e 
    30 // e + 0, 0 + e => e 
    31 // e * 0, 0 * e => 0
    31 // e * 0, 0 * e => 0
    32 // e * 1, 1 * e => e
    32 // e * 1, 1 * e => e
       
    33 //
       
    34 // (....0  ....)
    33 
    35 
    34 def simp(e: Exp) : Exp = e match {
    36 def simp(e: Exp) : Exp = e match {
    35   case N(n) => N(n)
    37   case N(n) => N(n)
    36   case Plus(e1, e2) => (simp(e1), simp(e2)) match {
    38   case Plus(e1, e2) => (simp(e1), simp(e2)) match {
    37     case (N(0), e2s) => e2s
    39     case (N(0), e2s) => e2s
    66   case Times(e1, e2) => rp(e1) ::: rp(e2) ::: List(TI) 
    68   case Times(e1, e2) => rp(e1) ::: rp(e2) ::: List(TI) 
    67 }
    69 }
    68 println(string(e2))
    70 println(string(e2))
    69 println(rp(e2))
    71 println(rp(e2))
    70 
    72 
    71 def comp(ls: List[Token], st: List[Int]) : Int = (ls, st) match {
    73 def comp(ls: List[Token], st: List[Int] = Nil) : Int = (ls, st) match {
    72   case (Nil, st) => st.head 
    74   case (Nil, st) => st.head 
    73   case (T(n)::rest, st) => comp(rest, n::st)
    75   case (T(n)::rest, st) => comp(rest, n::st)
    74   case (PL::rest, n1::n2::st) => comp(rest, n1 + n2::st)
    76   case (PL::rest, n1::n2::st) => comp(rest, n1 + n2::st)
    75   case (TI::rest, n1::n2::st) => comp(rest, n1 * n2::st)
    77   case (TI::rest, n1::n2::st) => comp(rest, n1 * n2::st)
    76 }
    78 }
    77 
    79 
    78 comp(rp(e), Nil)
    80 comp(rp(e))
    79 
    81 
    80 def proc(s: String) : Token = s match {
    82 def proc(s: String) : Token = s match {
    81   case  "+" => PL
    83   case  "+" => PL
    82   case  "*" => TI
    84   case  "*" => TI
    83   case  _ => T(s.toInt) 
    85   case  _ => T(s.toInt) 
   104               |5....9.6.
   106               |5....9.6.
   105               |..6.2..3.
   107               |..6.2..3.
   106               |1..5...92
   108               |1..5...92
   107               |..7.9.41.""".stripMargin.replaceAll("\\n", "")
   109               |..7.9.41.""".stripMargin.replaceAll("\\n", "")
   108 
   110 
       
   111 candidates(game0, (0, 0))
       
   112 
   109 type Pos = (Int, Int)
   113 type Pos = (Int, Int)
   110 val EmptyValue = '.'
   114 val EmptyValue = '.'
   111 val MaxValue = 9
   115 val MaxValue = 9
   112 
   116 
   113 val allValues = "123456789".toList
   117 val allValues = "123456789".toList
   122 
   126 
   123 def get_row(game: String, y: Int) = 
   127 def get_row(game: String, y: Int) = 
   124   indexes.map(col => game(y * MaxValue + col))
   128   indexes.map(col => game(y * MaxValue + col))
   125 def get_col(game: String, x: Int) = 
   129 def get_col(game: String, x: Int) = 
   126   indexes.map(row => game(x + row * MaxValue))
   130   indexes.map(row => game(x + row * MaxValue))
       
   131 
       
   132 get_row(game0, 0)
   127 
   133 
   128 def get_box(game: String, pos: Pos): List[Char] = {
   134 def get_box(game: String, pos: Pos): List[Char] = {
   129     def base(p: Int): Int = (p / 3) * 3
   135     def base(p: Int): Int = (p / 3) * 3
   130     val x0 = base(pos._1)
   136     val x0 = base(pos._1)
   131     val y0 = base(pos._2)
   137     val y0 = base(pos._2)
   152 //candidates(game0, (0,0))
   158 //candidates(game0, (0,0))
   153 
   159 
   154 def pretty(game: String): String = 
   160 def pretty(game: String): String = 
   155   "\n" + (game.sliding(MaxValue, MaxValue).mkString("\n"))
   161   "\n" + (game.sliding(MaxValue, MaxValue).mkString("\n"))
   156 
   162 
   157 
       
   158 def search(game: String): List[String] = {
   163 def search(game: String): List[String] = {
   159   if (isDone(game)) List(game)
   164   if (isDone(game)) List(game)
   160   else {
   165   else {
   161     val cs = candidates(game, emptyPosition(game))
   166     val cs = candidates(game, emptyPosition(game))
   162     cs.map(c => search(update(game, empty(game), c))).toList.flatten
   167     cs.map(c => search(update(game, empty(game), c))).toList.flatten
   163   }
   168   }
   164 }
   169 }
       
   170 
       
   171 List(List("sol1"), List("sol2", "sol3")).flatten
   165 
   172 
   166 search(game0).map(pretty)
   173 search(game0).map(pretty)
   167 
   174 
   168 val game1 = """23.915...
   175 val game1 = """23.915...
   169               |...2..54.
   176               |...2..54.
   216 
   223 
   217 
   224 
   218 // Tail recursion
   225 // Tail recursion
   219 //================
   226 //================
   220 
   227 
   221 
   228 @tailrec
   222 def fact(n: Long): Long = 
   229 def fact(n: BigInt): BigInt = 
   223   if (n == 0) 1 else n * fact(n - 1)
   230   if (n == 0) 1 else n * fact(n - 1)
   224 
   231 
   225 
   232 
   226 fact(10)              // ok
   233 fact(10)          
   227 fact(1000)            // silly
   234 fact(1000)        
   228 fact(10000)           // produces a stackoverflow
   235 fact(100000)       
   229 
   236 
   230 def factB(n: BigInt): BigInt = 
   237 def factB(n: BigInt): BigInt = 
   231   if (n == 0) 1 else n * factB(n - 1)
   238   if (n == 0) 1 else n * factB(n - 1)
   232 
   239 
   233 factB(1000)
       
   234 
       
   235 
       
   236 def factT(n: BigInt, acc: BigInt): BigInt =
   240 def factT(n: BigInt, acc: BigInt): BigInt =
   237   if (n == 0) acc else factT(n - 1, n * acc)
   241   if (n == 0) acc else factT(n - 1, n * acc)
   238 
   242 
       
   243 
       
   244 factB(1000)
       
   245 
       
   246 
       
   247 
       
   248 
   239 factT(10, 1)
   249 factT(10, 1)
   240 println(factT(100000, 1))
   250 println(factT(500000, 1))
       
   251 
       
   252 
       
   253 
       
   254 
   241 
   255 
   242 // there is a flag for ensuring a function is tail recursive
   256 // there is a flag for ensuring a function is tail recursive
   243 import scala.annotation.tailrec
   257 import scala.annotation.tailrec
   244 
   258 
   245 @tailrec
   259 @tailrec
   255 // functions
   269 // functions
   256 
   270 
   257 // tail recursive version that searches 
   271 // tail recursive version that searches 
   258 // for all Sudoku solutions
   272 // for all Sudoku solutions
   259 
   273 
   260 
   274 @tailrec
   261 def searchT(games: List[String], sols: List[String]): List[String] = games match {
   275 def searchT(games: List[String], sols: List[String]): List[String] = games match {
   262   case Nil => sols
   276   case Nil => sols
   263   case game::rest => {
   277   case game::rest => {
   264     if (isDone(game)) searchT(rest, game::sols)
   278     if (isDone(game)) searchT(rest, game::sols)
   265     else {
   279     else {
   303 
   317 
   304 searchT(List(game3), Nil).map(pretty)
   318 searchT(List(game3), Nil).map(pretty)
   305 search1T(List(game3)).map(pretty)
   319 search1T(List(game3)).map(pretty)
   306 
   320 
   307 // Moral: Whenever a recursive function is resource-critical
   321 // Moral: Whenever a recursive function is resource-critical
   308 // (i.e. works with large recursion depth), then you need to
   322 // (i.e. works with a large recursion depth), then you need to
   309 // write it in tail-recursive fashion.
   323 // write it in tail-recursive fashion.
   310 // 
   324 // 
   311 // Unfortuantely, Scala because of current limitations in 
   325 // Unfortuantely, Scala because of current limitations in 
   312 // the JVM is not as clever as other functional languages. It can 
   326 // the JVM is not as clever as other functional languages. It can 
   313 // only optimise "self-tail calls". This excludes the cases of 
   327 // only optimise "self-tail calls". This excludes the cases of 
   314 // multiple functions making tail calls to each other. Well,
   328 // multiple functions making tail calls to each other. Well,
   315 // nothing is perfect. 
   329 // nothing is perfect. 
   316 
   330 
   317 
   331 
   318 
   332 
   319 
       
   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 
       
   326 
       
   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 
       
   353 map(List(1, 2, 3, 4), (x: Int) => x.toString)
       
   354 
       
   355 
       
   356 
       
   357 // distinct / distinctBy
       
   358 
       
   359 val ls = List(1,2,3,3,2,4,3,2,1)
       
   360 ls.distinct
       
   361 
       
   362 ls.minBy(_._2)
       
   363 ls.sortBy(_._1)
       
   364 
       
   365 def distinctBy[B, C](xs: List[B], 
       
   366                      f: B => C, 
       
   367                      acc: List[C] = Nil): List[B] = xs match {
       
   368   case Nil => Nil
       
   369   case x::xs => {
       
   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 
       
   376 // distinctBy  with the identity function is 
       
   377 // just distinct
       
   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
       
   393 val z = id(Set[Int](1,2,3,4)) // Set[Int]
       
   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
       
   404 // to write the following incorrect code, and
       
   405 // only recovers by raising an exception
       
   406 // at runtime.
       
   407 
       
   408 // Object[] arr = new Integer[10];
       
   409 // arr[0] = "Hello World";
       
   410 
       
   411 
       
   412 // Scala gives you a compile-time error, which
       
   413 // is much better.
       
   414 
       
   415 var arr = Array[Int]()
       
   416 arr(0) = "Hello World"
       
   417 
   333 
   418 
   334 
   419 
   335 
   420 
   336 
   421 // Cool Stuff in Scala
   337 // Cool Stuff in Scala
   493 def charlist2rexp(s: List[Char]): Rexp = s match {
   409 def charlist2rexp(s: List[Char]): Rexp = s match {
   494   case Nil => ONE
   410   case Nil => ONE
   495   case c::Nil => CHAR(c)
   411   case c::Nil => CHAR(c)
   496   case c::s => SEQ(CHAR(c), charlist2rexp(s))
   412   case c::s => SEQ(CHAR(c), charlist2rexp(s))
   497 }
   413 }
       
   414 
   498 implicit def string2rexp(s: String): Rexp = 
   415 implicit def string2rexp(s: String): Rexp = 
   499   charlist2rexp(s.toList)
   416   charlist2rexp(s.toList)
   500 
   417 
       
   418 "(a|b)"
   501 
   419 
   502 val r1 = STAR("ab")
   420 val r1 = STAR("ab")
   503 val r2 = STAR(ALT("ab", "baa baa black sheep"))
   421 val r2 = (STAR("ab")) | (STAR("ba"))
   504 val r3 = STAR(SEQ("ab", ALT("a", "b")))
   422 val r3 = STAR(SEQ("ab", ALT("a", "b")))
   505 
   423 
   506 implicit def RexpOps (r: Rexp) = new {
   424 implicit def RexpOps (r: Rexp) = new {
   507   def | (s: Rexp) = ALT(r, s)
   425   def | (s: Rexp) = ALT(r, s)
   508   def % = STAR(r)
   426   def % = STAR(r)
   516   def ~ (r: Rexp) = SEQ(s, r)
   434   def ~ (r: Rexp) = SEQ(s, r)
   517   def ~ (r: String) = SEQ(s, r)
   435   def ~ (r: String) = SEQ(s, r)
   518 }
   436 }
   519 
   437 
   520 //example regular expressions
   438 //example regular expressions
   521 val digit = "0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9"
   439 val digit = ("0" | "1" | "2" | "3" | "4" | 
       
   440               "5" | "6" | "7" | "8" | "9")
   522 val sign = "+" | "-" | ""
   441 val sign = "+" | "-" | ""
   523 val number = sign ~ digit ~ digit.% 
   442 val number = sign ~ digit ~ digit.% 
   524 
   443 
   525 
   444 
   526 //
       
   527 // Object Oriented Programming in Scala
       
   528 //
       
   529 // =====================================
       
   530 
       
   531 abstract class Animal
       
   532 case class Bird(name: String) extends Animal {
       
   533    override def toString = name
       
   534 }
       
   535 case class Mammal(name: String) extends Animal
       
   536 case class Reptile(name: String) extends Animal
       
   537 
       
   538 Bird("Sparrow")
       
   539 
       
   540 println(Bird("Sparrow"))
       
   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
       
   551 // for constructors:
       
   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 
       
   566 // In mandelbrot.scala I used complex (imaginary) numbers 
       
   567 // and implemented the usual arithmetic operations for complex 
       
   568 // numbers.
       
   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 
       
   592 // ...to allow the notation n + m * i
       
   593 import scala.language.implicitConversions   
       
   594 
       
   595 val i = Complex(0, 1)
       
   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 
       
   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 !!!
       
   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 
       
   623 // BUT since we are completely IMMUTABLE, this is 
       
   624 // virtually of not concern to us.
       
   625 
       
   626 
       
   627 
       
   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 
       
   668 
       
   669 
       
   670 // DFAs in Scala  
       
   671 //===============
       
   672 import scala.util.Try
       
   673 
       
   674 
       
   675 // A is the state type
       
   676 // C is the input (usually characters)
       
   677 
       
   678 case class DFA[A, C](start: A,              // starting state
       
   679                      delta: (A, C) => A,    // transition function
       
   680                      fins:  A => Boolean) { // final states (Set)
       
   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 
       
   719 // another DFA with a Sink state
       
   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
       
   727 val sigma : (S, Char) => S = 
       
   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 
       
   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 
       
   752 
       
   753 
       
   754 
       
   755 // NFAs (Nondeterministic Finite Automata)
       
   756 
       
   757 
       
   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 
       
   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 
       
   767   def nexts(qs: Set[A], c: C) : Set[A] =
       
   768     qs.flatMap(next(_, c))
       
   769 
       
   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 
       
   800 // Q: Why the kerfuffle about the polymorphic types in DFAs/NFAs?
       
   801 // A: Subset construction. Here the state type for the DFA is
       
   802 //    sets of states.
       
   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 //
       
   827 // Do not evaluate arguments just yet:
       
   828 // this uses the => in front of the type
       
   829 // of the code-argument
       
   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 
       
   838 
   445 
   839 // Mind-Blowing Regular Expressions
   446 // Mind-Blowing Regular Expressions
   840 
   447 
   841 // same examples using the internal regexes
   448 // same examples using the internal regexes
   842 val evil = "(a*)*b"
   449 val evil = "(a*)*b"
   843 
   450 
   844 
   451 
   845 println("a" * 100)
   452 println("a" * 100)
   846 
   453 
   847 ("a" * 10 ++ "b").matches(evil)
   454 ("a" * 10000).matches(evil)
   848 ("a" * 10).matches(evil)
   455 ("a" * 10).matches(evil)
   849 ("a" * 10000).matches(evil)
   456 ("a" * 10000).matches(evil)
   850 ("a" * 20000).matches(evil)
   457 ("a" * 20000).matches(evil)
   851 ("a" * 50000).matches(evil)
   458 ("a" * 50000).matches(evil)
   852 
   459 
   853 time_needed(1, ("a" * 10000).matches(evil))
   460 time_needed(1, ("a" * 50000).matches(evil))