23 // remember  | 
    24 // remember  | 
    24 val lst = List(None, Some(1), Some(2), None, Some(3)).flatten  | 
    25 val lst = List(None, Some(1), Some(2), None, Some(3)).flatten  | 
    25   | 
    26   | 
    26   | 
    27   | 
    27 def my_flatten(xs: List[Option[Int]]): List[Int] = { | 
    28 def my_flatten(xs: List[Option[Int]]): List[Int] = { | 
    28   ...?  | 
    29   if (xs == Nil) Nil  | 
    29 }  | 
    30   else if (xs.head == None) my_flatten(xs.tail)  | 
    30   | 
    31   else xs.head.get :: my_flatten(xs.tail)  | 
    31   | 
    32 }  | 
    32   | 
    33   | 
    33   | 
    34   | 
         | 
    35   | 
         | 
    36 val lst = List(None, Some(1), Some(2), None, Some(3))  | 
    34   | 
    37   | 
    35 def my_flatten(lst: List[Option[Int]]): List[Int] = lst match { | 
    38 def my_flatten(lst: List[Option[Int]]): List[Int] = lst match { | 
    36   case Nil => Nil  | 
    39   case Nil => Nil  | 
    37   case None::xs => my_flatten(xs)  | 
    40   case None::xs => my_flatten(xs)  | 
    38   case Some(n)::xs => n::my_flatten(xs)  | 
    41   case Some(n)::xs => n::my_flatten(xs)  | 
    39 }  | 
    42 }  | 
         | 
    43   | 
         | 
    44 my_flatten(lst)  | 
         | 
    45   | 
         | 
    46 Nil == List()  | 
    40   | 
    47   | 
    41   | 
    48   | 
    42 // another example including a catch-all pattern  | 
    49 // another example including a catch-all pattern  | 
    43 def get_me_a_string(n: Int): String = n match { | 
    50 def get_me_a_string(n: Int): String = n match { | 
    44   case 0 => "zero"  | 
    51   case 0 => "zero"  | 
    45   case 1 => "one"  | 
    52   case 1 => "one"  | 
    46   case 2 => "two"  | 
    53   case 2 => "two"  | 
    47   case _ => "many"  | 
    54   case _ => "many"  | 
    48 }  | 
    55 }  | 
    49   | 
    56   | 
    50 get_me_a_string(0)  | 
    57 get_me_a_string(10)  | 
    51   | 
    58   | 
    52 // you can also have cases combined  | 
    59 // you can also have cases combined  | 
    53 def season(month: String) = month match { | 
    60 def season(month: String) = month match { | 
    54   case "March" | "April" | "May" => "It's spring"  | 
    61   case "March" | "April" | "May" => "It's spring"  | 
    55   case "June" | "July" | "August" => "It's summer"  | 
    62   case "June" | "July" | "August" => "It's summer"  | 
    62 // What happens if no case matches?  | 
    69 // What happens if no case matches?  | 
    63   | 
    70   | 
    64 println(season("foobar")) | 
    71 println(season("foobar")) | 
    65   | 
    72   | 
    66   | 
    73   | 
    67 // Collatz function on binary strings  | 
    74 // we can also match more complicated pattern  | 
         | 
    75 //  | 
         | 
    76 // let's look at the Collatz function on binary strings  | 
    68   | 
    77   | 
    69 // adding two binary strings in a very, very lazy manner  | 
    78 // adding two binary strings in a very, very lazy manner  | 
    70   | 
    79   | 
    71 def badd(s1: String, s2: String) : String =   | 
    80 def badd(s1: String, s2: String) : String =   | 
    72   (BigInt(s1, 2) + BigInt(s2, 2)).toString(2)  | 
    81   (BigInt(s1, 2) + BigInt(s2, 2)).toString(2)  | 
    73   | 
    82   | 
    74   | 
    83   | 
    75 // collatz function on binary numbers  | 
    84 "111".dropRight(1)  | 
         | 
    85 "111".last  | 
    76   | 
    86   | 
    77 def bcollatz(s: String) : Long = (s.dropRight(1), s.last) match { | 
    87 def bcollatz(s: String) : Long = (s.dropRight(1), s.last) match { | 
    78   case ("", '1') => 1                                  // we reached 1 | 
    88   case ("", '1') => 1                               // we reached 1 | 
    79   case (rest, '0') => 1 + bcollatz(rest)               // even number => divide by two  | 
    89   case (rest, '0') => 1 + bcollatz(rest)              | 
    80   case (rest, '1') => 1 + bcollatz(badd(s + '1', s))   // odd number => s + '1' is 2 * s + 1  | 
    90                                   // even number => divide by two  | 
    81                                                        //               add another s gives 3 * s + 1    | 
    91   case (rest, '1') => 1 + bcollatz(badd(s + '1', s))  | 
         | 
    92                                   // odd number => s + '1' is 2 * s + 1  | 
         | 
    93                                   // add another s gives 3 * s + 1    | 
    82 }   | 
    94 }   | 
    83   | 
    95   | 
    84 bcollatz(9.toBinaryString)  | 
    96 bcollatz(6.toBinaryString)  | 
    85 bcollatz(837799.toBinaryString)  | 
    97 bcollatz(837799.toBinaryString)  | 
    86 bcollatz(100000000000000000L.toBinaryString)  | 
    98 bcollatz(100000000000000000L.toBinaryString)  | 
    87 bcollatz(BigInt("1000000000000000000000000000000000000000000000000000000000000000000000000000").toString(2)) | 
    99 bcollatz(BigInt("1000000000000000000000000000000000000000000000000000000000000000000000000000").toString(2)) | 
    88   | 
   100   | 
    89   | 
   101   | 
    91   | 
   103   | 
    92 // User-defined Datatypes  | 
   104 // User-defined Datatypes  | 
    93 //========================  | 
   105 //========================  | 
    94   | 
   106   | 
    95 abstract class Colour  | 
   107 abstract class Colour  | 
    96 case class Red() extends Colour   | 
   108 case object Red extends Colour   | 
    97 case class Green() extends Colour   | 
   109 case object Green extends Colour   | 
    98 case class Blue() extends Colour  | 
   110 case object Blue extends Colour  | 
    99   | 
   111   | 
   100 def fav_colour(c: Colour) : Boolean = c match { | 
   112 def fav_colour(c: Colour) : Boolean = c match { | 
   101   case Red()   => false  | 
   113   case Red   => false  | 
   102   case Green() => true  | 
   114   case Green => true  | 
   103   case Blue()  => false   | 
   115   case Blue  => false   | 
   104 }  | 
   116 }  | 
         | 
   117   | 
         | 
   118 fav_colour(Green)  | 
   105   | 
   119   | 
   106   | 
   120   | 
   107 // actually colors can be written with "object",  | 
   121 // actually colors can be written with "object",  | 
   108 // because they do not take any arguments  | 
   122 // because they do not take any arguments  | 
   109   | 
   123   | 
   110   | 
   124   | 
   111   | 
   125 // ... a bit more useful: Roman Numerals  | 
   112 // Roman Numerals  | 
   126   | 
   113 abstract class RomanDigit   | 
   127 abstract class RomanDigit   | 
   114 case object I extends RomanDigit   | 
   128 case object I extends RomanDigit   | 
   115 case object V extends RomanDigit   | 
   129 case object V extends RomanDigit   | 
   116 case object X extends RomanDigit   | 
   130 case object X extends RomanDigit   | 
   117 case object L extends RomanDigit   | 
   131 case object L extends RomanDigit   | 
   136   case V::r    => 5 + RomanNumeral2Int(r)  | 
   150   case V::r    => 5 + RomanNumeral2Int(r)  | 
   137   case I::V::r => 4 + RomanNumeral2Int(r)  | 
   151   case I::V::r => 4 + RomanNumeral2Int(r)  | 
   138   case I::r    => 1 + RomanNumeral2Int(r)  | 
   152   case I::r    => 1 + RomanNumeral2Int(r)  | 
   139 }  | 
   153 }  | 
   140   | 
   154   | 
   141 RomanNumeral2Int(List(I,I,I,I))         // 4 (invalid roman number)  | 
         | 
   142 RomanNumeral2Int(List(I,V))             // 4  | 
   155 RomanNumeral2Int(List(I,V))             // 4  | 
         | 
   156 RomanNumeral2Int(List(I,I,I,I))         // 4 (invalid Roman number)  | 
   143 RomanNumeral2Int(List(V,I))             // 6  | 
   157 RomanNumeral2Int(List(V,I))             // 6  | 
   144 RomanNumeral2Int(List(I,X))             // 9  | 
   158 RomanNumeral2Int(List(I,X))             // 9  | 
   145 RomanNumeral2Int(List(M,C,M,L,X,X,I,X)) // 1979  | 
   159 RomanNumeral2Int(List(M,C,M,L,X,X,I,X)) // 1979  | 
   146 RomanNumeral2Int(List(M,M,X,V,I,I))     // 2017  | 
   160 RomanNumeral2Int(List(M,M,X,V,I,I))     // 2017  | 
   147   | 
   161   | 
   148   | 
   162   | 
   149   | 
   163   | 
   150 // another example  | 
   164 // another example  | 
   151 //=================  | 
   165 //=================  | 
   152   | 
   166   | 
   153 // Once upon a time, in a complete fictional country there were persons...  | 
   167 // Once upon a time, in a complete fictional country there were Persons...  | 
   154   | 
   168   | 
   155 abstract class Person  | 
   169 abstract class Person  | 
   156 case class King() extends Person  | 
   170 case object King extends Person  | 
   157 case class Peer(deg: String, terr: String, succ: Int) extends Person  | 
   171 case class Peer(deg: String, terr: String, succ: Int) extends Person  | 
   158 case class Knight(name: String) extends Person  | 
   172 case class Knight(name: String) extends Person  | 
   159 case class Peasant(name: String) extends Person  | 
   173 case class Peasant(name: String) extends Person  | 
   160   | 
   174 case object Clown extends Person  | 
   161   | 
   175   | 
   162 def title(p: Person): String = p match { | 
   176 def title(p: Person): String = p match { | 
   163   case King() => "His Majesty the King"  | 
   177   case King => "His Majesty the King"  | 
   164   case Peer(deg, terr, _) => s"The ${deg} of ${terr}" | 
   178   case Peer(deg, terr, _) => s"The ${deg} of ${terr}" | 
   165   case Knight(name) => s"Sir ${name}" | 
   179   case Knight(name) => s"Sir ${name}" | 
   166   case Peasant(name) => name  | 
   180   case Peasant(name) => name  | 
   167 }  | 
   181   case Clown => "My name is Boris Johnson"  | 
         | 
   182   | 
         | 
   183 }  | 
         | 
   184   | 
         | 
   185 title(Clown)  | 
         | 
   186   | 
   168   | 
   187   | 
   169   | 
   188   | 
   170 def superior(p1: Person, p2: Person): Boolean = (p1, p2) match { | 
   189 def superior(p1: Person, p2: Person): Boolean = (p1, p2) match { | 
   171   case (King(), _) => true  | 
   190   case (King, _) => true  | 
   172   case (Peer(_,_,_), Knight(_)) => true  | 
   191   case (Peer(_,_,_), Knight(_)) => true  | 
   173   case (Peer(_,_,_), Peasant(_)) => true  | 
   192   case (Peer(_,_,_), Peasant(_)) => true  | 
   174   case (Peer(_,_,_), Clown()) => true  | 
   193   case (Peer(_,_,_), Clown) => true  | 
   175   case (Knight(_), Peasant(_)) => true  | 
   194   case (Knight(_), Peasant(_)) => true  | 
   176   case (Knight(_), Clown()) => true  | 
   195   case (Knight(_), Clown) => true  | 
   177   case (Clown(), Peasant(_)) => true  | 
   196   case (Clown, Peasant(_)) => true  | 
   178   case _ => false  | 
   197   case _ => false  | 
   179 }  | 
   198 }  | 
   180   | 
   199   | 
   181 val people = List(Knight("David"),  | 
   200 val people = List(Knight("David"),  | 
   182                   Peer("Duke", "Norfolk", 84),  | 
   201                   Peer("Duke", "Norfolk", 84),  | 
   183                   Peasant("Christian"),  | 
   202                   Peasant("Christian"),  | 
   184                   King(),   | 
   203                   King,   | 
   185                   Clown())  | 
   204                   Clown)  | 
   186   | 
   205   | 
   187 println(people.sortWith(superior(_, _)).mkString(", ")) | 
   206 println(people.sortWith(superior(_, _)).mkString(", ")) | 
   188   | 
   207   | 
   189   | 
   208   | 
   190   | 
   209   | 
   273 //candidates(game0, (0,0))  | 
   293 //candidates(game0, (0,0))  | 
   274   | 
   294   | 
   275 def pretty(game: String): String =   | 
   295 def pretty(game: String): String =   | 
   276   "\n" + (game sliding (MaxValue, MaxValue) mkString "\n")  | 
   296   "\n" + (game sliding (MaxValue, MaxValue) mkString "\n")  | 
   277   | 
   297   | 
         | 
   298 /////////////////////  | 
   278 // not tail recursive   | 
   299 // not tail recursive   | 
   279 def search(game: String): List[String] = { | 
   300 def search(game: String): List[String] = { | 
   280   if (isDone(game)) List(game)  | 
   301   if (isDone(game)) List(game)  | 
   281   else { | 
   302   else { | 
   282     val cs = candidates(game, emptyPosition(game))  | 
   303     val cs = candidates(game, emptyPosition(game))  | 
   283     cs.map(c => search(update(game, empty(game), c))).toList.flatten  | 
   304     cs.map(c => search(update(game, empty(game), c))).toList.flatten  | 
   284   }  | 
   305   }  | 
   285 }  | 
   306 }  | 
   286   | 
   307   | 
   287 // tail recursive version that searches   | 
   308 // tail recursive version that searches   | 
   288 // for all solution  | 
   309 // for all solutions  | 
         | 
   310   | 
   289 def searchT(games: List[String], sols: List[String]): List[String] = games match { | 
   311 def searchT(games: List[String], sols: List[String]): List[String] = games match { | 
   290   case Nil => sols  | 
   312   case Nil => sols  | 
   291   case game::rest => { | 
   313   case game::rest => { | 
   292     if (isDone(game)) searchT(rest, game::sols)  | 
   314     if (isDone(game)) searchT(rest, game::sols)  | 
   293     else { | 
   315     else { | 
   295       searchT(cs.map(c => update(game, empty(game), c)) ::: rest, sols)  | 
   317       searchT(cs.map(c => update(game, empty(game), c)) ::: rest, sols)  | 
   296     }  | 
   318     }  | 
   297   }  | 
   319   }  | 
   298 }  | 
   320 }  | 
   299   | 
   321   | 
         | 
   322 searchT(List(game3), List()).map(pretty)  | 
         | 
   323   | 
         | 
   324   | 
   300 // tail recursive version that searches   | 
   325 // tail recursive version that searches   | 
   301 // for a single solution  | 
   326 // for a single solution  | 
         | 
   327   | 
   302 def search1T(games: List[String]): Option[String] = games match { | 
   328 def search1T(games: List[String]): Option[String] = games match { | 
   303   case Nil => None  | 
   329   case Nil => None  | 
   304   case game::rest => { | 
   330   case game::rest => { | 
   305     if (isDone(game)) Some(game)  | 
   331     if (isDone(game)) Some(game)  | 
   306     else { | 
   332     else { | 
   307       val cs = candidates(game, emptyPosition(game))  | 
   333       val cs = candidates(game, emptyPosition(game))  | 
   308       search1T(cs.map(c => update(game, empty(game), c)) ::: rest)  | 
   334       search1T(cs.map(c => update(game, empty(game), c)) ::: rest)  | 
   309     }  | 
   335     }  | 
   310   }  | 
   336   }  | 
   311 }  | 
   337 }  | 
         | 
   338   | 
         | 
   339 search1T(List(game3)).map(pretty)  | 
   312   | 
   340   | 
   313 // game with multiple solutions  | 
   341 // game with multiple solutions  | 
   314 val game3 = """.8...9743  | 
   342 val game3 = """.8...9743  | 
   315               |.5...8.1.  | 
   343               |.5...8.1.  | 
   316               |.1.......  | 
   344               |.1.......  | 
   319               |...3....6  | 
   347               |...3....6  | 
   320               |.......7.  | 
   348               |.......7.  | 
   321               |.3.5...8.  | 
   349               |.3.5...8.  | 
   322               |9724...5.""".stripMargin.replaceAll("\\n", "") | 
   350               |9724...5.""".stripMargin.replaceAll("\\n", "") | 
   323   | 
   351   | 
   324 searchT(List(game3), List()).map(pretty)  | 
   352 searchT(List(game3), Nil).map(pretty)  | 
   325 search1T(List(game3)).map(pretty)  | 
   353 search1T(List(game3)).map(pretty)  | 
   326   | 
   354   | 
   327 // Moral: Whenever a recursive function is resource-critical  | 
   355 // Moral: Whenever a recursive function is resource-critical  | 
   328 // (i.e. works with large recursion depths), then you need to  | 
   356 // (i.e. works with large recursion depth), then you need to  | 
   329 // write it in tail-recursive fashion.  | 
   357 // write it in tail-recursive fashion.  | 
   330 //   | 
   358 //   | 
   331 // Unfortuantely, Scala because of current limitations in   | 
   359 // Unfortuantely, Scala because of current limitations in   | 
   332 // the JVM is not as clever as other functional languages. It can   | 
   360 // the JVM is not as clever as other functional languages. It can   | 
   333 // only optimise "self-tail calls". This excludes the cases of   | 
   361 // only optimise "self-tail calls". This excludes the cases of   | 
   347 def length_string_list(lst: List[String]): Int = lst match { | 
   375 def length_string_list(lst: List[String]): Int = lst match { | 
   348   case Nil => 0  | 
   376   case Nil => 0  | 
   349   case x::xs => 1 + length_string_list(xs)  | 
   377   case x::xs => 1 + length_string_list(xs)  | 
   350 }  | 
   378 }  | 
   351   | 
   379   | 
         | 
   380 def length_int_list(lst: List[Int]): Int = lst match { | 
         | 
   381   case Nil => 0  | 
         | 
   382   case x::xs => 1 + length_int_list(xs)  | 
         | 
   383 }  | 
         | 
   384   | 
   352 length_string_list(List("1", "2", "3", "4")) | 
   385 length_string_list(List("1", "2", "3", "4")) | 
   353   | 
   386 length_int_list(List(1, 2, 3, 4))  | 
   354   | 
   387   | 
         | 
   388 //-----  | 
   355 def length[A](lst: List[A]): Int = lst match { | 
   389 def length[A](lst: List[A]): Int = lst match { | 
   356   case Nil => 0  | 
   390   case Nil => 0  | 
   357   case x::xs => 1 + length(xs)  | 
   391   case x::xs => 1 + length(xs)  | 
   358 }  | 
   392 }  | 
   359   | 
   393 length(List("1", "2", "3", "4")) | 
   360   | 
   394 length(List(King, Knight("foo"), Clown)) | 
   361 def map_int_list(lst: List[Int], f: Int => Int): List[Int] = lst match { | 
   395 length(List(1, 2, 3, 4))  | 
         | 
   396   | 
         | 
   397 def map[A, B](lst: List[A], f: A => B): List[B] = lst match { | 
   362   case Nil => Nil  | 
   398   case Nil => Nil  | 
   363   case x::xs => f(x)::map_int_list(xs, f)   | 
   399   case x::xs => f(x)::map_int_list(xs, f)   | 
   364 }  | 
   400 }  | 
   365   | 
   401   | 
   366 map_int_list(List(1, 2, 3, 4), square)  | 
   402 map_int_list(List(1, 2, 3, 4), square)  |