progs/lecture3.scala
changeset 158 94b11ac19b41
parent 155 371acb50643d
child 170 37b1bfcdba79
--- a/progs/lecture3.scala	Fri Nov 24 09:10:53 2017 +0000
+++ b/progs/lecture3.scala	Mon Nov 27 01:15:36 2017 +0000
@@ -6,9 +6,10 @@
 
 // A powerful tool which is supposed to come to Java in a few years
 // time (https://www.youtube.com/watch?v=oGll155-vuQ)...Scala already
-// has it for many years. Other functional languages have it for
-// decades. I think I would refuse to program in a language that
-// does not have pattern matching....its is just so elegant. ;o)
+// has it for many years. Other functional languages have it already for
+// decades. I think I would be really upset if a programming language 
+// I have to use does not have pattern matching....its is just so 
+// useful. ;o)
 
 // The general schema:
 //
@@ -25,12 +26,14 @@
 
 
 def my_flatten(xs: List[Option[Int]]): List[Int] = {
-  ...?
+  if (xs == Nil) Nil
+  else if (xs.head == None) my_flatten(xs.tail)
+  else xs.head.get :: my_flatten(xs.tail)
 }
 
 
 
-
+val lst = List(None, Some(1), Some(2), None, Some(3))
 
 def my_flatten(lst: List[Option[Int]]): List[Int] = lst match {
   case Nil => Nil
@@ -38,6 +41,10 @@
   case Some(n)::xs => n::my_flatten(xs)
 }
 
+my_flatten(lst)
+
+Nil == List()
+
 
 // another example including a catch-all pattern
 def get_me_a_string(n: Int): String = n match {
@@ -47,7 +54,7 @@
   case _ => "many"
 }
 
-get_me_a_string(0)
+get_me_a_string(10)
 
 // you can also have cases combined
 def season(month: String) = month match {
@@ -64,7 +71,9 @@
 println(season("foobar"))
 
 
-// Collatz function on binary strings
+// we can also match more complicated pattern
+//
+// let's look at the Collatz function on binary strings
 
 // adding two binary strings in a very, very lazy manner
 
@@ -72,16 +81,19 @@
   (BigInt(s1, 2) + BigInt(s2, 2)).toString(2)
 
 
-// collatz function on binary numbers
+"111".dropRight(1)
+"111".last
 
 def bcollatz(s: String) : Long = (s.dropRight(1), s.last) match {
-  case ("", '1') => 1                                  // we reached 1
-  case (rest, '0') => 1 + bcollatz(rest)               // even number => divide by two
-  case (rest, '1') => 1 + bcollatz(badd(s + '1', s))   // odd number => s + '1' is 2 * s + 1
-                                                       //               add another s gives 3 * s + 1  
+  case ("", '1') => 1                               // we reached 1
+  case (rest, '0') => 1 + bcollatz(rest)            
+                                  // even number => divide by two
+  case (rest, '1') => 1 + bcollatz(badd(s + '1', s))
+                                  // odd number => s + '1' is 2 * s + 1
+                                  // add another s gives 3 * s + 1  
 } 
 
-bcollatz(9.toBinaryString)
+bcollatz(6.toBinaryString)
 bcollatz(837799.toBinaryString)
 bcollatz(100000000000000000L.toBinaryString)
 bcollatz(BigInt("1000000000000000000000000000000000000000000000000000000000000000000000000000").toString(2))
@@ -93,23 +105,25 @@
 //========================
 
 abstract class Colour
-case class Red() extends Colour 
-case class Green() extends Colour 
-case class Blue() extends 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 
+  case Red   => false
+  case Green => true
+  case Blue  => false 
 }
 
+fav_colour(Green)
+
 
 // actually colors can be written with "object",
 // because they do not take any arguments
 
 
+// ... a bit more useful: Roman Numerals
 
-// Roman Numerals
 abstract class RomanDigit 
 case object I extends RomanDigit 
 case object V extends RomanDigit 
@@ -138,8 +152,8 @@
   case I::r    => 1 + RomanNumeral2Int(r)
 }
 
-RomanNumeral2Int(List(I,I,I,I))         // 4 (invalid roman number)
 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
@@ -150,39 +164,44 @@
 // another example
 //=================
 
-// Once upon a time, in a complete fictional country there were persons...
+// Once upon a time, in a complete fictional country there were Persons...
 
 abstract class Person
-case class King() extends 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
-
+case object Clown extends Person
 
 def title(p: Person): String = p match {
-  case King() => "His Majesty the King"
+  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
+  case Clown => "My name is Boris Johnson"
+
 }
 
+title(Clown)
+
+
 
 def superior(p1: Person, p2: Person): Boolean = (p1, p2) match {
-  case (King(), _) => true
+  case (King, _) => true
   case (Peer(_,_,_), Knight(_)) => true
   case (Peer(_,_,_), Peasant(_)) => true
-  case (Peer(_,_,_), Clown()) => true
+  case (Peer(_,_,_), Clown) => true
   case (Knight(_), Peasant(_)) => true
-  case (Knight(_), Clown()) => true
-  case (Clown(), 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())
+                  King, 
+                  Clown)
 
 println(people.sortWith(superior(_, _)).mkString(", "))
 
@@ -202,6 +221,7 @@
 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
@@ -275,6 +295,7 @@
 def pretty(game: String): String = 
   "\n" + (game sliding (MaxValue, MaxValue) mkString "\n")
 
+/////////////////////
 // not tail recursive 
 def search(game: String): List[String] = {
   if (isDone(game)) List(game)
@@ -285,7 +306,8 @@
 }
 
 // tail recursive version that searches 
-// for all solution
+// for all solutions
+
 def searchT(games: List[String], sols: List[String]): List[String] = games match {
   case Nil => sols
   case game::rest => {
@@ -297,8 +319,12 @@
   }
 }
 
+searchT(List(game3), List()).map(pretty)
+
+
 // tail recursive version that searches 
 // for a single solution
+
 def search1T(games: List[String]): Option[String] = games match {
   case Nil => None
   case game::rest => {
@@ -310,6 +336,8 @@
   }
 }
 
+search1T(List(game3)).map(pretty)
+
 // game with multiple solutions
 val game3 = """.8...9743
               |.5...8.1.
@@ -321,11 +349,11 @@
               |.3.5...8.
               |9724...5.""".stripMargin.replaceAll("\\n", "")
 
-searchT(List(game3), List()).map(pretty)
+searchT(List(game3), Nil).map(pretty)
 search1T(List(game3)).map(pretty)
 
 // Moral: Whenever a recursive function is resource-critical
-// (i.e. works with large recursion depths), then you need to
+// (i.e. works with large recursion depth), then you need to
 // write it in tail-recursive fashion.
 // 
 // Unfortuantely, Scala because of current limitations in 
@@ -349,16 +377,24 @@
   case x::xs => 1 + length_string_list(xs)
 }
 
-length_string_list(List("1", "2", "3", "4"))
+def length_int_list(lst: List[Int]): Int = lst match {
+  case Nil => 0
+  case x::xs => 1 + length_int_list(xs)
+}
 
+length_string_list(List("1", "2", "3", "4"))
+length_int_list(List(1, 2, 3, 4))
 
+//-----
 def length[A](lst: List[A]): Int = lst match {
   case Nil => 0
   case x::xs => 1 + length(xs)
 }
-
+length(List("1", "2", "3", "4"))
+length(List(King, Knight("foo"), Clown))
+length(List(1, 2, 3, 4))
 
-def map_int_list(lst: List[Int], f: Int => Int): List[Int] = lst match {
+def map[A, B](lst: List[A], f: A => B): List[B] = lst match {
   case Nil => Nil
   case x::xs => f(x)::map_int_list(xs, f) 
 }
@@ -371,12 +407,12 @@
 
 
 
+
+
 // Cool Stuff
 //============
 
 
-
-
 // Implicits 
 //===========
 //
@@ -410,6 +446,7 @@
 case class STAR(r: Rexp) extends Rexp               // star         r*
 
 
+
 // (ab)*
 val r0 = STAR(SEQ(CHAR('a'), CHAR('b')))
 
@@ -427,7 +464,7 @@
 
 
 val r1 = STAR("ab")
-val r2 = STAR("")
+val r2 = STAR(ALT("ab"))
 val r3 = STAR(ALT("ab", "baa baa black sheep"))
 
 implicit def RexpOps (r: Rexp) = new {
@@ -462,7 +499,13 @@
 // reason not to.
 
 // You can be productive on Day 1, but the language is deep.
+//
+// http://scalapuzzlers.com
+//
+// http://www.latkin.org/blog/2017/05/02/when-the-scala-compiler-doesnt-help/
 
-// I like best about Scala that it lets me write
+List(1, 2, 3) contains "your mom"
+
+// I like best about Scala that it lets me often write
 // concise, readable code.