--- 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
+