progs/lecture3.scala
changeset 318 029e2862bb4e
parent 223 c6453f3547ec
child 320 cdfb2ce30a3d
equal deleted inserted replaced
317:607ceabeeffc 318:029e2862bb4e
    48 // some starting URLs for the crawler
    48 // some starting URLs for the crawler
    49 val startURL = """https://nms.kcl.ac.uk/christian.urban/"""
    49 val startURL = """https://nms.kcl.ac.uk/christian.urban/"""
    50 crawl(startURL, 2)
    50 crawl(startURL, 2)
    51 
    51 
    52 
    52 
       
    53 // User-defined Datatypes
       
    54 //========================
       
    55 
       
    56 
       
    57 abstract class Colour
       
    58 case object Red extends Colour 
       
    59 case object Green extends Colour 
       
    60 case object Blue extends Colour
       
    61 
       
    62 def fav_colour(c: Colour) : Boolean = c match {
       
    63   case Red   => false
       
    64   case Green => true
       
    65   case Blue  => false 
       
    66 }
       
    67 
       
    68 fav_colour(Green)
       
    69 
       
    70 
       
    71 // ... a tiny bit more useful: Roman Numerals
       
    72 
       
    73 abstract class RomanDigit 
       
    74 case object I extends RomanDigit 
       
    75 case object V extends RomanDigit 
       
    76 case object X extends RomanDigit 
       
    77 case object L extends RomanDigit 
       
    78 case object C extends RomanDigit 
       
    79 case object D extends RomanDigit 
       
    80 case object M extends RomanDigit 
       
    81 
       
    82 type RomanNumeral = List[RomanDigit] 
       
    83 
       
    84 List(X,I)
       
    85 
       
    86 /*
       
    87 I -> 1
       
    88 II -> 2
       
    89 III  -> 3
       
    90 IV -> 4
       
    91 V -> 5
       
    92 VI -> 6
       
    93 VII -> 7
       
    94 VIII -> 8
       
    95 IX -> 9
       
    96 X -> X
       
    97 */
       
    98 
       
    99 def RomanNumeral2Int(rs: RomanNumeral): Int = rs match { 
       
   100   case Nil => 0
       
   101   case M::r    => 1000 + RomanNumeral2Int(r)  
       
   102   case C::M::r => 900 + RomanNumeral2Int(r)
       
   103   case D::r    => 500 + RomanNumeral2Int(r)
       
   104   case C::D::r => 400 + RomanNumeral2Int(r)
       
   105   case C::r    => 100 + RomanNumeral2Int(r)
       
   106   case X::C::r => 90 + RomanNumeral2Int(r)
       
   107   case L::r    => 50 + RomanNumeral2Int(r)
       
   108   case X::L::r => 40 + RomanNumeral2Int(r)
       
   109   case X::r    => 10 + RomanNumeral2Int(r)
       
   110   case I::X::r => 9 + RomanNumeral2Int(r)
       
   111   case V::r    => 5 + RomanNumeral2Int(r)
       
   112   case I::V::r => 4 + RomanNumeral2Int(r)
       
   113   case I::r    => 1 + RomanNumeral2Int(r)
       
   114 }
       
   115 
       
   116 RomanNumeral2Int(List(I,V))             // 4
       
   117 RomanNumeral2Int(List(I,I,I,I))         // 4 (invalid Roman number)
       
   118 RomanNumeral2Int(List(V,I))             // 6
       
   119 RomanNumeral2Int(List(I,X))             // 9
       
   120 RomanNumeral2Int(List(M,C,M,L,X,X,I,X)) // 1979
       
   121 RomanNumeral2Int(List(M,M,X,V,I,I))     // 2017
       
   122 
       
   123 
       
   124 // another example
       
   125 //=================
       
   126 
       
   127 // Once upon a time, in a complete fictional 
       
   128 // country there were Persons...
       
   129 
       
   130 
       
   131 abstract class Person
       
   132 case object King extends Person
       
   133 case class Peer(deg: String, terr: String, succ: Int) extends Person
       
   134 case class Knight(name: String) extends Person
       
   135 case class Peasant(name: String) extends Person
       
   136 
       
   137 
       
   138 def title(p: Person): String = p match {
       
   139   case King => "His Majesty the King"
       
   140   case Peer(deg, terr, _) => s"The ${deg} of ${terr}"
       
   141   case Knight(name) => s"Sir ${name}"
       
   142   case Peasant(name) => name
       
   143 }
       
   144 
       
   145 def superior(p1: Person, p2: Person): Boolean = (p1, p2) match {
       
   146   case (King, _) => true
       
   147   case (Peer(_,_,_), Knight(_)) => true
       
   148   case (Peer(_,_,_), Peasant(_)) => true
       
   149   case (Peer(_,_,_), Clown) => true
       
   150   case (Knight(_), Peasant(_)) => true
       
   151   case (Knight(_), Clown) => true
       
   152   case (Clown, Peasant(_)) => true
       
   153   case _ => false
       
   154 }
       
   155 
       
   156 val people = List(Knight("David"), 
       
   157                   Peer("Duke", "Norfolk", 84), 
       
   158                   Peasant("Christian"), 
       
   159                   King, 
       
   160                   Clown)
       
   161 
       
   162 println(people.sortWith(superior).mkString("\n"))
       
   163 
       
   164 
       
   165 // String interpolations as patterns
       
   166 
       
   167 val date = "2000-01-01"
       
   168 val s"$year-$month-$day" = date
       
   169 
       
   170 def parse_date(date: String) = date match {
       
   171   case s"$year-$month-$day" => Some((year.toInt, month.toInt, day.toInt))
       
   172   case s"$day/$month/$year" => Some((year.toInt, month.toInt, day.toInt))
       
   173   case _ => None
       
   174 } 
       
   175 
       
   176 
       
   177 
    53 
   178 
    54 // User-defined Datatypes and Pattern Matching
   179 // User-defined Datatypes and Pattern Matching
    55 //=============================================
   180 //=============================================
       
   181 
       
   182 
    56 
   183 
    57 abstract class Exp
   184 abstract class Exp
    58 case class N(n: Int) extends Exp                  // for numbers
   185 case class N(n: Int) extends Exp                  // for numbers
    59 case class Plus(e1: Exp, e2: Exp) extends Exp
   186 case class Plus(e1: Exp, e2: Exp) extends Exp
    60 case class Times(e1: Exp, e2: Exp) extends Exp
   187 case class Times(e1: Exp, e2: Exp) extends Exp
   320 jumps(List(1,3,6,1,0,9)).minBy(_.length)
   447 jumps(List(1,3,6,1,0,9)).minBy(_.length)
   321 jumps(List(2,3,1,1,2,4,2,0,1,1)).minBy(_.length)
   448 jumps(List(2,3,1,1,2,4,2,0,1,1)).minBy(_.length)
   322 
   449 
   323 
   450 
   324 
   451 
   325 
   452 // Tail Recursion
       
   453 //================
       
   454 
       
   455 
       
   456 def fact(n: Long): Long = 
       
   457   if (n == 0) 1 else n * fact(n - 1)
       
   458 
       
   459 fact(10)              //ok
       
   460 fact(10000)           // produces a stackoverflow
       
   461 
       
   462 def factT(n: BigInt, acc: BigInt): BigInt =
       
   463   if (n == 0) acc else factT(n - 1, n * acc)
       
   464 
       
   465 factT(10, 1)
       
   466 factT(100000, 1)
       
   467 
       
   468 // there is a flag for ensuring a function is tail recursive
       
   469 import scala.annotation.tailrec
       
   470 
       
   471 @tailrec
       
   472 def factT(n: BigInt, acc: BigInt): BigInt =
       
   473   if (n == 0) acc else factT(n - 1, n * acc)
       
   474 
       
   475 
       
   476 
       
   477 // for tail-recursive functions the Scala compiler
       
   478 // generates loop-like code, which does not need
       
   479 // to allocate stack-space in each recursive
       
   480 // call; Scala can do this only for tail-recursive
       
   481 // functions
   326 
   482 
   327 
   483 
   328 
   484 
   329 
   485 
   330 
   486