diff -r 15f1fca879c5 -r 94b11ac19b41 progs/lecture3.scala --- 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.