diff -r 607ceabeeffc -r 029e2862bb4e progs/lecture3.scala --- a/progs/lecture3.scala Mon Nov 11 14:04:22 2019 +0000 +++ b/progs/lecture3.scala Tue Nov 12 00:41:00 2019 +0000 @@ -50,10 +50,137 @@ crawl(startURL, 2) +// User-defined Datatypes +//======================== + + +abstract class Colour +case object Red extends Colour +case object Green extends Colour +case object Blue extends Colour + +def fav_colour(c: Colour) : Boolean = c match { + case Red => false + case Green => true + case Blue => false +} + +fav_colour(Green) + + +// ... a tiny bit more useful: Roman Numerals + +abstract class RomanDigit +case object I extends RomanDigit +case object V extends RomanDigit +case object X extends RomanDigit +case object L extends RomanDigit +case object C extends RomanDigit +case object D extends RomanDigit +case object M extends RomanDigit + +type RomanNumeral = List[RomanDigit] + +List(X,I) + +/* +I -> 1 +II -> 2 +III -> 3 +IV -> 4 +V -> 5 +VI -> 6 +VII -> 7 +VIII -> 8 +IX -> 9 +X -> X +*/ + +def RomanNumeral2Int(rs: RomanNumeral): Int = rs match { + case Nil => 0 + case M::r => 1000 + RomanNumeral2Int(r) + case C::M::r => 900 + RomanNumeral2Int(r) + case D::r => 500 + RomanNumeral2Int(r) + case C::D::r => 400 + RomanNumeral2Int(r) + case C::r => 100 + RomanNumeral2Int(r) + case X::C::r => 90 + RomanNumeral2Int(r) + case L::r => 50 + RomanNumeral2Int(r) + case X::L::r => 40 + RomanNumeral2Int(r) + case X::r => 10 + RomanNumeral2Int(r) + case I::X::r => 9 + RomanNumeral2Int(r) + case V::r => 5 + RomanNumeral2Int(r) + case I::V::r => 4 + RomanNumeral2Int(r) + case I::r => 1 + RomanNumeral2Int(r) +} + +RomanNumeral2Int(List(I,V)) // 4 +RomanNumeral2Int(List(I,I,I,I)) // 4 (invalid Roman number) +RomanNumeral2Int(List(V,I)) // 6 +RomanNumeral2Int(List(I,X)) // 9 +RomanNumeral2Int(List(M,C,M,L,X,X,I,X)) // 1979 +RomanNumeral2Int(List(M,M,X,V,I,I)) // 2017 + + +// another example +//================= + +// Once upon a time, in a complete fictional +// country there were Persons... + + +abstract class Person +case object King extends Person +case class Peer(deg: String, terr: String, succ: Int) extends Person +case class Knight(name: String) extends Person +case class Peasant(name: String) extends Person + + +def title(p: Person): String = p match { + case King => "His Majesty the King" + case Peer(deg, terr, _) => s"The ${deg} of ${terr}" + case Knight(name) => s"Sir ${name}" + case Peasant(name) => name +} + +def superior(p1: Person, p2: Person): Boolean = (p1, p2) match { + case (King, _) => true + case (Peer(_,_,_), Knight(_)) => true + case (Peer(_,_,_), Peasant(_)) => true + case (Peer(_,_,_), Clown) => true + case (Knight(_), Peasant(_)) => true + case (Knight(_), Clown) => true + case (Clown, Peasant(_)) => true + case _ => false +} + +val people = List(Knight("David"), + Peer("Duke", "Norfolk", 84), + Peasant("Christian"), + King, + Clown) + +println(people.sortWith(superior).mkString("\n")) + + +// String interpolations as patterns + +val date = "2000-01-01" +val s"$year-$month-$day" = date + +def parse_date(date: String) = date match { + case s"$year-$month-$day" => Some((year.toInt, month.toInt, day.toInt)) + case s"$day/$month/$year" => Some((year.toInt, month.toInt, day.toInt)) + case _ => None +} + + + // User-defined Datatypes and Pattern Matching //============================================= + + abstract class Exp case class N(n: Int) extends Exp // for numbers case class Plus(e1: Exp, e2: Exp) extends Exp @@ -322,8 +449,37 @@ +// Tail Recursion +//================ +def fact(n: Long): Long = + if (n == 0) 1 else n * fact(n - 1) + +fact(10) //ok +fact(10000) // produces a stackoverflow + +def factT(n: BigInt, acc: BigInt): BigInt = + if (n == 0) acc else factT(n - 1, n * acc) + +factT(10, 1) +factT(100000, 1) + +// there is a flag for ensuring a function is tail recursive +import scala.annotation.tailrec + +@tailrec +def factT(n: BigInt, acc: BigInt): BigInt = + if (n == 0) acc else factT(n - 1, n * acc) + + + +// for tail-recursive functions the Scala compiler +// generates loop-like code, which does not need +// to allocate stack-space in each recursive +// call; Scala can do this only for tail-recursive +// functions +