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