|      1 // Scala Lecture 4 |      1 // Scala Lecture 4 | 
|      2 //================= |      2 //================= | 
|      3  |      3  | 
|         |      4 // pattern-matching | 
|      4 // tail-recursion |      5 // tail-recursion | 
|      5 // polymorphic types |      6 // polymorphic types | 
|      6 // implicits |      7  | 
|      7  |      8  | 
|      8 import scala.annotation.tailrec |      9  | 
|      9  |     10 // Pattern Matching | 
|     10 def fact(n: BigInt): BigInt =  |     11 //================== | 
|     11   if (n == 0) 1 else n * fact(n - 1) |     12  | 
|     12        |     13 // A powerful tool which has even landed in Java during  | 
|     13   |     14 // the last few years (https://inside.java/2021/06/13/podcast-017/). | 
|     14 def factT(n: BigInt, acc: BigInt): BigInt = |     15 // ...Scala already has it for many years and the concept is | 
|     15   if (n == 0) acc else factT(n - 1, n * acc) |     16 // older than your friendly lecturer, that is stone old  ;o) | 
|     16  |     17  | 
|     17  |     18 // The general schema: | 
|     18 println(factT(1000000), 1))  |     19 // | 
|     19  |     20 //    expression match { | 
|     20  |     21 //       case pattern1 => expression1 | 
|     21 def foo[A](args: List[A]) = ??? |     22 //       case pattern2 => expression2 | 
|     22  |     23 //       ... | 
|     23 foo(List("1","2","3","4")) |     24 //       case patternN => expressionN | 
|     24  |     25 //    } | 
|     25  |     26  | 
|     26 // from knight1.scala |     27  | 
|     27 def first(xs: List[Pos], f: Pos => Option[Path]) : Option[Path] = ??? |     28 // recall | 
|     28  |     29 def len(xs: List[Int]) : Int = { | 
|     29 // should be |     30     if (xs == Nil) 0 | 
|     30 def first[A, B](xs: List[A], f: A => Option[B]) : Option[B] = ??? |     31     else 1 + len(xs.tail) | 
|         |     32 }     | 
|         |     33  | 
|         |     34 def len(xs: List[Int]) : Int = xs match { | 
|         |     35     case Nil => 0 | 
|         |     36     case _::xs => 1 + len(xs) | 
|         |     37 }   | 
|         |     38  | 
|         |     39 len(Nil) | 
|         |     40 len(List(1,2,3,4)) | 
|         |     41  | 
|         |     42  | 
|         |     43 List(1,2,3,4).map(x => x * x) | 
|         |     44  | 
|         |     45 def my_map_int(lst: List[Int], f: Int => Int) : List[Int] =  | 
|         |     46   lst match { | 
|         |     47     case Nil => Nil | 
|         |     48     case foo::xs => f(foo) :: my_map_int(xs, f) | 
|         |     49   } | 
|         |     50  | 
|         |     51 def my_map_option(opt: Option[Int], f: Int => Int) : Option[Int] =  | 
|         |     52   opt match { | 
|         |     53     case None => None | 
|         |     54     case Some(x) => { | 
|         |     55       Some(f(x)) | 
|         |     56     } | 
|         |     57   } | 
|         |     58  | 
|         |     59 my_map_option(None, x => x * x) | 
|         |     60 my_map_option(Some(8), x => x * x) | 
|         |     61  | 
|         |     62  | 
|         |     63 // you can also have cases combined | 
|         |     64 def season(month: String) : String = month match { | 
|         |     65   case "March" | "April" | "May" => "It's spring" | 
|         |     66   case "June" | "July" | "August" => "It's summer" | 
|         |     67   case "September" | "October" | "November" => "It's autumn" | 
|         |     68   case "December" => "It's winter" | 
|         |     69   case "January" | "February" => "It's unfortunately winter" | 
|         |     70   case _ => "Wrong month" | 
|         |     71 } | 
|         |     72  | 
|         |     73 // pattern-match on integers | 
|         |     74  | 
|         |     75 def fib(n: Int) : Int = n match {  | 
|         |     76   case 0 | 1 => 1 | 
|         |     77   case _ => fib(n - 1) + fib(n - 2) | 
|         |     78 } | 
|         |     79  | 
|         |     80 fib(10) | 
|         |     81  | 
|         |     82 // pattern-match on results | 
|         |     83  | 
|         |     84 // Silly: fizz buzz | 
|         |     85 def fizz_buzz(n: Int) : String = (n % 3, n % 5) match { | 
|         |     86   case (0, 0) => "fizz buzz" | 
|         |     87   case (0, _) => "fizz" | 
|         |     88   case (_, 0) => "buzz" | 
|         |     89   case _ => n.toString   | 
|         |     90 } | 
|         |     91  | 
|         |     92 for (n <- 1 to 20)  | 
|         |     93  println(fizz_buzz(n)) | 
|         |     94  | 
|         |     95 // guards in pattern-matching | 
|         |     96  | 
|         |     97 def foo(xs: List[Int]) : String = xs match { | 
|         |     98   case Nil => s"this list is empty" | 
|         |     99   case x :: xs if x % 2 == 0  | 
|         |    100      => s"the first elemnt is even" | 
|         |    101   case x if len(x) == | 
|         |    102      => s"this list has exactly two elements"    | 
|         |    103   case x :: y :: rest if x == y | 
|         |    104      => s"this has two elemnts that are the same" | 
|         |    105   case hd :: tl => s"this list is standard $hd::$tl" | 
|         |    106 } | 
|         |    107  | 
|         |    108 foo(Nil) | 
|         |    109 foo(List(1,2,3)) | 
|         |    110 foo(List(1,1)) | 
|         |    111 foo(List(1,1,2,3)) | 
|         |    112 foo(List(2,2,2,3)) | 
|         |    113  | 
|         |    114  | 
|         |    115  | 
|         |    116  | 
|         |    117 abstract class Colour | 
|         |    118 case object Red extends Colour  | 
|         |    119 case object Green extends Colour  | 
|         |    120 case object Blue extends Colour | 
|         |    121 case object Yellow extends Colour | 
|         |    122  | 
|         |    123  | 
|         |    124 def fav_colour(c: Colour) : Boolean = c match { | 
|         |    125   case Green => true | 
|         |    126   case Red => true | 
|         |    127   case _  => false  | 
|         |    128 } | 
|         |    129  | 
|         |    130 fav_colour(Blue) | 
|         |    131  | 
|         |    132  | 
|         |    133 // ... a tiny bit more useful: Roman Numerals | 
|         |    134  | 
|         |    135 sealed abstract class RomanDigit  | 
|         |    136 case object I extends RomanDigit  | 
|         |    137 case object V extends RomanDigit  | 
|         |    138 case object X extends RomanDigit  | 
|         |    139 case object L extends RomanDigit  | 
|         |    140 case object C extends RomanDigit  | 
|         |    141 case object D extends RomanDigit  | 
|         |    142 case object M extends RomanDigit  | 
|         |    143  | 
|         |    144 type RomanNumeral = List[RomanDigit]  | 
|         |    145  | 
|         |    146 List(I, M,C,D,X,X,V,I,I, A) | 
|         |    147  | 
|         |    148 /* | 
|         |    149 I    -> 1 | 
|         |    150 II   -> 2 | 
|         |    151 III  -> 3 | 
|         |    152 IV   -> 4 | 
|         |    153 V    -> 5 | 
|         |    154 VI   -> 6 | 
|         |    155 VII  -> 7 | 
|         |    156 VIII -> 8 | 
|         |    157 IX   -> 9 | 
|         |    158 X    -> 10 | 
|         |    159 */ | 
|         |    160  | 
|         |    161 def RomanNumeral2Int(rs: RomanNumeral): Int = rs match {  | 
|         |    162   case Nil => 0 | 
|         |    163   case M::r    => 1000 + RomanNumeral2Int(r)   | 
|         |    164   case C::M::r => 900 + RomanNumeral2Int(r) | 
|         |    165   case D::r    => 500 + RomanNumeral2Int(r) | 
|         |    166   case C::D::r => 400 + RomanNumeral2Int(r) | 
|         |    167   case C::r    => 100 + RomanNumeral2Int(r) | 
|         |    168   case X::C::r => 90 + RomanNumeral2Int(r) | 
|         |    169   case L::r    => 50 + RomanNumeral2Int(r) | 
|         |    170   case X::L::r => 40 + RomanNumeral2Int(r) | 
|         |    171   case X::r    => 10 + RomanNumeral2Int(r) | 
|         |    172   case I::X::r => 9 + RomanNumeral2Int(r) | 
|         |    173   case V::r    => 5 + RomanNumeral2Int(r) | 
|         |    174   case I::V::r => 4 + RomanNumeral2Int(r) | 
|         |    175   case I::r    => 1 + RomanNumeral2Int(r) | 
|         |    176 } | 
|         |    177  | 
|         |    178 RomanNumeral2Int(List(I,V))             // 4 | 
|         |    179 RomanNumeral2Int(List(I,I,I,I))         // 4 (invalid Roman number) | 
|         |    180 RomanNumeral2Int(List(V,I))             // 6 | 
|         |    181 RomanNumeral2Int(List(I,X))             // 9 | 
|         |    182 RomanNumeral2Int(List(M,C,M,L,X,X,I,X)) // 1979 | 
|         |    183 RomanNumeral2Int(List(M,M,X,V,I,I))     // 2017 | 
|         |    184  | 
|         |    185 abstract class Tree | 
|         |    186 case class Leaf(x: Int) | 
|         |    187 case class Branch(tl: Tree, tr: Tree) | 
|         |    188  | 
|         |    189  | 
|         |    190 abstract class Rexp | 
|         |    191 case object ZERO extends Rexp                      // matches nothing | 
|         |    192 case object ONE extends Rexp                       // matches the empty string | 
|         |    193 case class CHAR(c: Char) extends Rexp              // matches a character c | 
|         |    194 case class ALT(r1: Rexp, r2: Rexp) extends Rexp    // alternative | 
|         |    195 case class SEQ(r1: Rexp, r2: Rexp) extends Rexp    // sequence | 
|         |    196 case class STAR(r: Rexp) extends Rexp              // star | 
|         |    197  | 
|         |    198 def depth(r: Rexp) : Int = r match { | 
|         |    199   case ZERO => 1 | 
|         |    200   case ONE => 1 | 
|         |    201   case CHAR(_) => 1 | 
|         |    202   case ALT(r1, r2) => 1 + List(depth(r1), depth(r2)).max | 
|         |    203   case SEQ(r1, r2) => 1 + List(depth(r1), depth(r2)).max | 
|         |    204   case STAR(r1) => 1 + depth(r1) | 
|         |    205 } | 
|         |    206  | 
|         |    207  | 
|         |    208 // Trees (example of an Algebraic Datatype) | 
|         |    209  | 
|         |    210  | 
|         |    211 abstract class Tree | 
|         |    212 case class Leaf(x: Int) extends Tree | 
|         |    213 case class Node(s: String, left: Tree, right: Tree) extends Tree  | 
|         |    214  | 
|         |    215 val lf = Leaf(20) | 
|         |    216 val tr = Node("foo", Leaf(10), Leaf(23)) | 
|         |    217  | 
|         |    218 val lst : List[Tree] = List(lf, tr) | 
|         |    219  | 
|     31  |    220  | 
|     32  |    221  | 
|     33 // expressions (essentially trees) |    222 // expressions (essentially trees) | 
|     34  |    223  | 
|     35 abstract class Exp |    224 sealed abstract class Exp | 
|     36 case class N(n: Int) extends Exp                  // for numbers |    225 case class N(n: Int) extends Exp                  // for numbers | 
|     37 case class Plus(e1: Exp, e2: Exp) extends Exp |    226 case class Plus(e1: Exp, e2: Exp) extends Exp | 
|     38 case class Times(e1: Exp, e2: Exp) extends Exp |    227 case class Times(e1: Exp, e2: Exp) extends Exp | 
|     39  |    228  | 
|     40 def string(e: Exp) : String = e match { |    229 def string(e: Exp) : String = e match { | 
|    114 } |    309 } | 
|    115  |    310  | 
|    116 comp("1 2 + 4 * 5 + 3 +".split(" ").toList.map(proc), Nil) |    311 comp("1 2 + 4 * 5 + 3 +".split(" ").toList.map(proc), Nil) | 
|    117  |    312  | 
|    118  |    313  | 
|    119 // Polymorphic Types |         | 
|    120 //=================== |         | 
|    121  |         | 
|    122 // You do not want to write functions like contains, first,  |         | 
|    123 // length and so on for every type of lists. |         | 
|    124  |         | 
|    125 def length_int_list(lst: List[Int]): Int = lst match { |         | 
|    126   case Nil => 0 |         | 
|    127   case _::xs => 1 + length_int_list(xs) |         | 
|    128 } |         | 
|    129  |         | 
|    130 length_int_list(List(1, 2, 3, 4)) |         | 
|    131  |         | 
|    132 def length_string_list(lst: List[String]): Int = lst match { |         | 
|    133   case Nil => 0 |         | 
|    134   case _::xs => 1 + length_string_list(xs) |         | 
|    135 } |         | 
|    136  |         | 
|    137 length_string_list(List("1", "2", "3", "4")) |         | 
|    138  |         | 
|    139  |         | 
|    140 // you can make the function parametric in type(s) |         | 
|    141  |         | 
|    142 def length[A](lst: List[A]): Int = lst match { |         | 
|    143   case Nil => 0 |         | 
|    144   case x::xs => 1 + length(xs) |         | 
|    145 } |         | 
|    146 length(List("1", "2", "3", "4")) |         | 
|    147 length(List(1, 2, 3, 4)) |         | 
|    148  |         | 
|    149  |         | 
|    150 length[String](List(1, 2, 3, 4)) |         | 
|    151  |         | 
|    152  |         | 
|    153 def map[A, B](lst: List[A], f: A => B): List[B] = lst match { |         | 
|    154   case Nil => Nil |         | 
|    155   case x::xs => f(x)::map(xs, f)  |         | 
|    156 } |         | 
|    157  |         | 
|    158 map(List(1, 2, 3, 4), (x: Int) => x.toString) |         | 
|    159  |         | 
|    160  |         | 
|    161 // from knight1.scala |         | 
|    162 def first(xs: List[Pos], f: Pos => Option[Path]) : Option[Path] = ??? |         | 
|    163  |         | 
|    164 // should be |         | 
|    165 def first[A, B](xs: List[A], f: A => Option[B]) : Option[B] = ??? |         | 
|    166  |         | 
|    167 // Type inference is local in Scala |         | 
|    168  |         | 
|    169 def id[T](x: T) : T = x |         | 
|    170  |         | 
|    171 val x = id(322)          // Int |         | 
|    172 val y = id("hey")        // String |         | 
|    173 val z = id(Set(1,2,3,4)) // Set[Int] |         | 
|    174  |         | 
|    175  |         | 
|    176 // The type variable concept in Scala can get really complicated. |         | 
|    177 // |         | 
|    178 // - variance (OO) |         | 
|    179 // - bounds (subtyping) |         | 
|    180 // - quantification |         | 
|    181  |         | 
|    182 // Java has issues with this too: Java allows |         | 
|    183 // to write the following incorrect code, and |         | 
|    184 // only recovers by raising an exception |         | 
|    185 // at runtime. |         | 
|    186  |         | 
|    187 // Object[] arr = new Integer[10]; |         | 
|    188 // arr[0] = "Hello World"; |         | 
|    189  |         | 
|    190  |         | 
|    191 // Scala gives you a compile-time error, which |         | 
|    192 // is much better. |         | 
|    193  |         | 
|    194 var arr = Array[Int]() |         | 
|    195 arr(0) = "Hello World" |         | 
|    196  |         | 
|    197  |         | 
|    198  |         | 
|    199  |         | 
|    200 // Function definitions again |         | 
|    201 //============================ |         | 
|    202  |         | 
|    203 // variable arguments |         | 
|    204  |         | 
|    205 def printAll(strings: String*) = { |         | 
|    206   strings.foreach(println) |         | 
|    207 } |         | 
|    208  |         | 
|    209 printAll() |         | 
|    210 printAll("foo") |         | 
|    211 printAll("foo", "bar") |         | 
|    212 printAll("foo", "bar", "baz") |         | 
|    213  |         | 
|    214 // pass a list to the varargs field |         | 
|    215 val fruits = List("apple", "banana", "cherry") |         | 
|    216  |         | 
|    217 printAll(fruits: _*) |         | 
|    218  |         | 
|    219  |         | 
|    220 // you can also implement your own string interpolations |         | 
|    221 import scala.language.implicitConversions |         | 
|    222 import scala.language.reflectiveCalls |         | 
|    223  |         | 
|    224 implicit def sring_inters(sc: StringContext) = new { |         | 
|    225     def i(args: Any*): String = s"${sc.s(args:_*)}\n" |         | 
|    226 } |         | 
|    227  |         | 
|    228 i"add ${3+2} ${3 * 3}"  |         | 
|    229  |         | 
|    230  |         | 
|    231 // default arguments |         | 
|    232  |         | 
|    233 def length[A](xs: List[A]) : Int = xs match { |         | 
|    234   case Nil => 0 |         | 
|    235   case _ :: tail => 1 + length(tail) |         | 
|    236 } |         | 
|    237  |         | 
|    238 def lengthT[A](xs: List[A], acc : Int = 0) : Int = xs match { |         | 
|    239   case Nil => acc |         | 
|    240   case _ :: tail => lengthT(tail, 1 + acc) |         | 
|    241 } |         | 
|    242  |         | 
|    243 lengthT(List.fill(100000)(1)) |         | 
|    244  |         | 
|    245  |         | 
|    246 def fact(n: BigInt, acc: BigInt = 1): BigInt = |         | 
|    247   if (n == 0) acc else fact(n - 1, n * acc) |         | 
|    248  |         | 
|    249 fact(10) |         | 
|    250  |         | 
|    251  |         | 
|    252  |         | 
|    253 // currying    (Haskell Curry) |         | 
|    254  |         | 
|    255 def add(x: Int, y: Int) = x + y |         | 
|    256  |         | 
|    257 List(1,2,3,4,5).map(x => add(3, x)) |         | 
|    258  |         | 
|    259 def add2(x: Int)(y: Int) = x + y |         | 
|    260  |         | 
|    261 List(1,2,3,4,5).map(add2(3)) |         | 
|    262  |         | 
|    263 val a3 : Int => Int = add2(3) |         | 
|    264  |         | 
|    265 // currying helps sometimes with type inference |         | 
|    266  |         | 
|    267 def find[A](xs: List[A])(pred: A => Boolean): Option[A] = { |         | 
|    268   xs match { |         | 
|    269     case Nil => None |         | 
|    270     case hd :: tl => |         | 
|    271       if (pred(hd)) Some(hd) else find(tl)(pred) |         | 
|    272   } |         | 
|    273 } |         | 
|    274  |         | 
|    275 find(List(1, 2, 3))(x => x % 2 == 0) |         | 
|    276  |         | 
|    277 // Source.fromURL(url)(encoding) |         | 
|    278 // Source.fromFile(name)(encoding) |         | 
|    279  |         | 
|    280  |         | 
|    281 // Tail recursion |    314 // Tail recursion | 
|    282 //================ |    315 //================ | 
|    283  |    316  | 
|    284 def fact(n: Int): Int =  |    317 def fact(n: BigInt): BigInt =  | 
|    285   if (n == 0) 1 else n * fact(n - 1) |    318   if (n == 0) 1 else n * fact(n - 1) | 
|    286  |    319  | 
|    287  |    320  | 
|    288 fact(10)           |    321 fact(10)           | 
|    289 fact(1000)         |    322 fact(1000)         | 
|    290 fact(100000)        |    323 fact(100000)        | 
|    291  |    324  | 
|    292 def factB(n: BigInt): BigInt =  |         | 
|    293   if (n == 0) 1 else n * factB(n - 1) |         | 
|    294  |    325  | 
|    295 def factT(n: BigInt, acc: BigInt): BigInt = |    326 def factT(n: BigInt, acc: BigInt): BigInt = | 
|    296   if (n == 0) acc else factT(n - 1, n * acc) |    327   if (n == 0) acc else factT(n - 1, n * acc) | 
|    297  |    328  | 
|    298  |    329  | 
|    299 factB(1000) |         | 
|    300  |         | 
|    301  |         | 
|    302 factT(10, 1) |    330 factT(10, 1) | 
|    303 println(factT(500000, 1)) |    331 println(factT(100000, 1)) | 
|    304  |    332  | 
|    305  |    333  | 
|    306 // there is a flag for ensuring a function is tail recursive |    334 // there is a flag for ensuring a function is tail recursive | 
|    307 import scala.annotation.tailrec |    335 import scala.annotation.tailrec | 
|    308  |    336  | 
|    325 // Unfortuantely, Scala because of current limitations in  |    353 // Unfortuantely, Scala because of current limitations in  | 
|    326 // the JVM is not as clever as other functional languages. It can  |    354 // the JVM is not as clever as other functional languages. It can  | 
|    327 // only optimise "self-tail calls". This excludes the cases of  |    355 // only optimise "self-tail calls". This excludes the cases of  | 
|    328 // multiple functions making tail calls to each other. Well, |    356 // multiple functions making tail calls to each other. Well, | 
|    329 // nothing is perfect.  |    357 // nothing is perfect.  | 
|         |    358  | 
|         |    359  | 
|         |    360  | 
|         |    361 // Polymorphic Types | 
|         |    362 //=================== | 
|         |    363  | 
|         |    364 // You do not want to write functions like contains, first,  | 
|         |    365 // length and so on for every type of lists. | 
|         |    366  | 
|         |    367 def length_int_list(lst: List[Int]): Int = lst match { | 
|         |    368   case Nil => 0 | 
|         |    369   case _::xs => 1 + length_int_list(xs) | 
|         |    370 } | 
|         |    371  | 
|         |    372 length_int_list(List(1, 2, 3, 4)) | 
|         |    373  | 
|         |    374 def length_string_list(lst: List[String]): Int = lst match { | 
|         |    375   case Nil => 0 | 
|         |    376   case _::xs => 1 + length_string_list(xs) | 
|         |    377 } | 
|         |    378  | 
|         |    379 length_string_list(List("1", "2", "3", "4")) | 
|         |    380  | 
|         |    381  | 
|         |    382 // you can make the function parametric in type(s) | 
|         |    383  | 
|         |    384 def length[A](lst: List[A]): Int = lst match { | 
|         |    385   case Nil => 0 | 
|         |    386   case x::xs => 1 + length(xs) | 
|         |    387 } | 
|         |    388 length(List("1", "2", "3", "4")) | 
|         |    389 length(List(1, 2, 3, 4)) | 
|         |    390  | 
|         |    391  | 
|         |    392 length[String](List(1, 2, 3, 4)) | 
|         |    393  | 
|         |    394  | 
|         |    395 def map[A, B](lst: List[A], f: A => B): List[B] = lst match { | 
|         |    396   case Nil => Nil | 
|         |    397   case x::xs => f(x)::map(xs, f)  | 
|         |    398 } | 
|         |    399  | 
|         |    400 map(List(1, 2, 3, 4), (x: Int) => x.toString) | 
|         |    401  | 
|         |    402  | 
|         |    403 // should be | 
|         |    404 def first[A, B](xs: List[A], f: A => Option[B]) : Option[B] = ??? | 
|         |    405  | 
|         |    406 // Type inference is local in Scala | 
|         |    407  | 
|         |    408 def id[T](x: T) : T = x | 
|         |    409  | 
|         |    410 val x = id(322)          // Int | 
|         |    411 val y = id("hey")        // String | 
|         |    412 val z = id(Set(1,2,3,4)) // Set[Int] | 
|         |    413  | 
|         |    414  | 
|         |    415 // The type variable concept in Scala can get really complicated. | 
|         |    416 // | 
|         |    417 // - variance (OO) | 
|         |    418 // - bounds (subtyping) | 
|         |    419 // - quantification | 
|         |    420  | 
|         |    421 // Java has issues with this too: Java allows | 
|         |    422 // to write the following incorrect code, and | 
|         |    423 // only recovers by raising an exception | 
|         |    424 // at runtime. | 
|         |    425  | 
|         |    426 // Object[] arr = new Integer[10]; | 
|         |    427 // arr[0] = "Hello World"; | 
|         |    428  | 
|         |    429  | 
|         |    430 // Scala gives you a compile-time error, which | 
|         |    431 // is much better. | 
|         |    432  | 
|         |    433 var arr = Array[Int]() | 
|         |    434 arr(0) = "Hello World" | 
|         |    435  | 
|         |    436  | 
|         |    437  | 
|         |    438  | 
|         |    439 // Function definitions again | 
|         |    440 //============================ | 
|         |    441  | 
|         |    442 // variable arguments | 
|         |    443  | 
|         |    444 def printAll(strings: String*) = { | 
|         |    445   strings.foreach(println) | 
|         |    446 } | 
|         |    447  | 
|         |    448 printAll() | 
|         |    449 printAll("foo") | 
|         |    450 printAll("foo", "bar") | 
|         |    451 printAll("foo", "bar", "baz") | 
|         |    452  | 
|         |    453 // pass a list to the varargs field | 
|         |    454 val fruits = List("apple", "banana", "cherry") | 
|         |    455  | 
|         |    456 printAll(fruits: _*) | 
|         |    457  | 
|         |    458  | 
|         |    459 // you can also implement your own string interpolations | 
|         |    460 import scala.language.implicitConversions | 
|         |    461 import scala.language.reflectiveCalls | 
|         |    462  | 
|         |    463 implicit def sring_inters(sc: StringContext) = new { | 
|         |    464     def i(args: Any*): String = s"${sc.s(args:_*)}\n" | 
|         |    465 } | 
|         |    466  | 
|         |    467 i"add ${3+2} ${3 * 3}"  | 
|         |    468  | 
|         |    469  | 
|         |    470 // default arguments | 
|         |    471  | 
|         |    472 def length[A](xs: List[A]) : Int = xs match { | 
|         |    473   case Nil => 0 | 
|         |    474   case _ :: tail => 1 + length(tail) | 
|         |    475 } | 
|         |    476  | 
|         |    477 def lengthT[A](xs: List[A], acc : Int = 0) : Int = xs match { | 
|         |    478   case Nil => acc | 
|         |    479   case _ :: tail => lengthT(tail, 1 + acc) | 
|         |    480 } | 
|         |    481  | 
|         |    482 lengthT(List.fill(100000)(1)) | 
|         |    483  | 
|         |    484  | 
|         |    485 def fact(n: BigInt, acc: BigInt = 1): BigInt = | 
|         |    486   if (n == 0) acc else fact(n - 1, n * acc) | 
|         |    487  | 
|         |    488 fact(10) | 
|         |    489  | 
|         |    490  | 
|         |    491  | 
|         |    492 // currying    (Haskell Curry) | 
|         |    493  | 
|         |    494 def add(x: Int, y: Int) = x + y | 
|         |    495  | 
|         |    496 List(1,2,3,4,5).map(x => add(3, x)) | 
|         |    497  | 
|         |    498 def add2(x: Int)(y: Int) = x + y | 
|         |    499  | 
|         |    500 List(1,2,3,4,5).map(add2(3)) | 
|         |    501  | 
|         |    502 val a3 : Int => Int = add2(3) | 
|         |    503  | 
|         |    504 // currying helps sometimes with type inference | 
|         |    505  | 
|         |    506 def find[A](xs: List[A])(pred: A => Boolean): Option[A] = { | 
|         |    507   xs match { | 
|         |    508     case Nil => None | 
|         |    509     case hd :: tl => | 
|         |    510       if (pred(hd)) Some(hd) else find(tl)(pred) | 
|         |    511   } | 
|         |    512 } | 
|         |    513  | 
|         |    514 find(List(1, 2, 3))(x => x % 2 == 0) | 
|         |    515  | 
|         |    516 // Source.fromURL(url)(encoding) | 
|         |    517 // Source.fromFile(name)(encoding) | 
|         |    518  | 
|         |    519  | 
|    330  |    520  | 
|    331  |    521  | 
|    332  |    522  | 
|    333  |    523  | 
|    334  |    524  |