progs/lecture4.scala
changeset 481 e03a0100ec46
parent 455 557d18cce0f0
equal deleted inserted replaced
480:a623dd1f2898 481:e03a0100ec46
     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 {
    42   case Plus(e1, e2) => s"(${string(e1)} + ${string(e2)})" 
   231   case Plus(e1, e2) => s"(${string(e1)} + ${string(e2)})" 
    43   case Times(e1, e2) => s"(${string(e1)} * ${string(e2)})"
   232   case Times(e1, e2) => s"(${string(e1)} * ${string(e2)})"
    44 }
   233 }
    45 
   234 
    46 val e = Plus(N(9), Times(N(3), N(4)))
   235 val e = Plus(N(9), Times(N(3), N(4)))
       
   236 println(e.toString)
    47 println(string(e))
   237 println(string(e))
    48 
   238 
    49 def eval(e: Exp) : Int = e match {
   239 def eval(e: Exp) : Int = e match {
    50   case N(n) => n
   240   case N(n) => n
    51   case Plus(e1, e2) => eval(e1) + eval(e2) 
   241   case Plus(e1, e2) => eval(e1) + eval(e2) 
    57 // simplification rules:
   247 // simplification rules:
    58 // e + 0, 0 + e => e 
   248 // e + 0, 0 + e => e 
    59 // e * 0, 0 * e => 0
   249 // e * 0, 0 * e => 0
    60 // e * 1, 1 * e => e
   250 // e * 1, 1 * e => e
    61 //
   251 //
    62 // (....0  ....)
   252 // (....9 ....)
    63 
   253 
    64 def simp(e: Exp) : Exp = e match {
   254 def simp(e: Exp) : Exp = e match {
    65   case N(n) => N(n)
   255   case N(n) => N(n)
    66   case Plus(e1, e2) => (simp(e1), simp(e2)) match {
   256   case Plus(e1, e2) => (simp(e1), simp(e2)) match {
    67     case (N(0), e2s) => e2s
   257     case (N(0), e2s) => e2s
    81 val e2 = Times(Plus(N(0), N(1)), Plus(N(0), N(9)))
   271 val e2 = Times(Plus(N(0), N(1)), Plus(N(0), N(9)))
    82 println(string(e2))
   272 println(string(e2))
    83 println(string(simp(e2)))
   273 println(string(simp(e2)))
    84 
   274 
    85 
   275 
       
   276 
       
   277 
       
   278 
       
   279 
       
   280 
    86 // Tokens and Reverse Polish Notation
   281 // Tokens and Reverse Polish Notation
    87 abstract class Token
   282 abstract class Token
    88 case class T(n: Int) extends Token
   283 case class T(n: Int) extends Token
    89 case object PL extends Token
   284 case object PL extends Token
    90 case object TI extends Token
   285 case object TI extends Token
   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