Express in a functional style with pattern matching
def printList (xs:List[Int]) : Unit =
val xs = List(11,21,31)
printList (xs)
Visit all elements of a list
def printList (xs:List[Int]) : Unit = xs match
case Nil => ()
case y::ys =>
printList (ys)
val xs = List(11,21,31)
printList (xs)
Print an element when visiting
def printList (xs:List[Int]) : Unit = xs match
case Nil => ()
case y::ys =>
println (y)
printList (ys)
val xs = List(11,21,31)
printList (xs)
Format every element before printing
def printList (xs:List[Int]) : Unit = xs match
case Nil => ()
case y::ys =>
println ("0x%02x".format(y))
printList (ys)
val xs = List(11,21,31)
printList (xs)
Different type of list
def printList (xs:List[List[Int]]) : Unit = xs match
case Nil => ()
case y::ys =>
println (y.length)
printList (ys)
val xss = List(List(11,21,31),List(),List(41,51))
printList (xss)
Generalize the idea of processing every element
def foreach (xs:List[Int], f:Int=>Unit) : Unit = xs match
case Nil => ()
case y::ys =>
f (y)
foreach (ys, f)
val xs = List(11,21,31)
foreach (xs, println)
Customize with changed function argument
def foreach (xs:List[Int], f:Int=>Unit) : Unit = xs match
case Nil => ()
case y::ys =>
f (y)
foreach (ys, f)
def printHex (x:Int) = println("0x%02x".format(x))
val xs = List(11,21,31)
foreach (xs, printHex)
Generalize the type of list with parameters
def foreach [X] (xs:List[X], f:X=>Unit) : Unit = xs match
case Nil => ()
case y::ys =>
f (y)
foreach (ys, f)
def printLength (xs:List[Int]) = println (xs.length)
val xss = List(List(11,21,31),List(),List(41,51))
foreach (xss, printLength)
Use a lambda expression (anonymous function)
def foreach [X] (xs:List[X], f:X=>Unit) : Unit = xs match
case Nil => ()
case y::ys =>
f (y)
foreach (ys, f)
val xss = List(List(11,21,31),List(),List(41,51))
foreach (xss, (xs:List[Int]) => println (xs.length))
Using the builtin List class foreach method
xs.foreach ((x:Int) => println (x))
def print (x:Int) = println (x) val print = (x:Int) => println (x)
xs.foreach (print) xs.foreach (print)
xs.foreach (x => println ("0x%02x".format(x)))
def foreach [X] (xs:List[X], f:X=>Unit) : Unit = ...
X is a type parameter
f is a parameter of function type: (X=>Unit)
XUnitval xs = List(1,2,3)
foreachxs.foreach (x => println (x))
xs.foreach (println)
for x <- xs do println (x)
val add = (x:Int, y:Int) => x+y
add(11,21)
val add = (_:Int) + (_:Int)
add(11,21)
var add : (Int,Int)=>Int = null
add = (x,y) => x+y
add = _ + _
add(11,21)
Use a compound expression
def foreach [X] (xs:List[X], f:X=>Unit) : Unit =
println("call foreach(%s)".format(xs))
xs match
case Nil => ()
case y::ys =>
f (y)
foreach (ys, f)
println("rtrn foreach(%s)".format(xs))
val xs = List(21,31)
foreach (xs, (x:Int) => ())
call foreach(List(21, 31))
call foreach(List(31))
call foreach(List())
rtrn foreach(List())
rtrn foreach(List(31))
rtrn foreach(List(21, 31))
def reference (xs:List[Int]) : List[Int] = xs
xs eq reference(xs) /* reference equality */
xs == reference(xs) /* value equality */
res1: Boolean = true
res2: Boolean = true
def copy (xs:List[Int]) : List[Int] = xs match
case Nil => Nil
case y::ys => y::copy(ys)
xs eq copy(xs) /* reference equality */
xs == copy(xs) /* value equality */
res1: Boolean = false
res2: Boolean = true
Return a transformed copy of a list
def map (xs:List[Int]) : List[String] = xs match
case Nil => Nil
case y::ys => ("0x%02x".format (y)) :: map (ys)
val xs = List(11,21,31)
map(xs)
Change the type of list
def map (xs:List[List[Int]]) : List[Int] = xs match
case Nil => Nil
case y::ys => (y.length) :: map (ys)
val xss = List(List(11,21,31),List(),List(41,51))
map(xss)
implement generic iterate, generalize element function
def map (xs:List[Int], f:Int=>String) : List[String] = xs match
case Nil => Nil
case y::ys => f(y) :: map (ys, f)
val xs = List(11,21,31)
map(xs, "0x%02x".format (_))
abstracting types
def map [X,Y] (xs:List[X], f:X=>Y) : List[Y] = xs match
case Nil => Nil
case y::ys => f(y) :: map (ys, f)
val xs = List(11,21,31)
map(xs, (y:Int) => "0x%02x".format (y))
copy is just a specialization of map with f:X=>X = x=>x
def map [X,Y] (xs:List[X], f:X=>Y) : List[Y] = xs match
case Nil => Nil
case y::ys => f(y) :: map (ys, f)
val xs = List(11,21,31)
map(xs, x => x)
foreach is just a specialization of map with f:X=>Unit
def map [X,Y] (xs:List[X], f:X=>Y) : List[Y] = xs match
case Nil => Nil
case y::ys => f(y) :: map (ys, f)
val xs = List(11,21,31)
map(xs, (x:Int) => println ("0x%02x".format(x)))
mapxs.map ("0x%02x".format (_))
Map a List[List[Int]] to a List[Int]
List(List(11,21,31),List(),List(41,51)).map (_.length)
res1: List[Int] = List(3, 0, 2)
Map a List[String] to a List[Int]
List("hi", "it's", "me").map (_.length)
res1: List[Int] = List(2, 4, 2)
Map a List[Int] to a List[Int]
List(1, 2, 3, 4).map (_ + 1)
res1: List[Int] = List(2, 3, 4, 5)
mapxs.map (x => "0x%02x".format(x))
foreachxs.foreach (x => println ("0x%02x".format(x)))
yieldfor x <- xs yield "0x%02x".format(x)
dofor x <- xs do println ("0x%02x".format(x))
Revisit the copy operation
def copy [X] (xs:List[X]) : List[X] = xs match
case Nil => Nil
case y::ys => y :: copy (ys)
val zs = (0 to 7).toList
copy(zs)
Copy only elements that satisfy a predicate f
def filter [X] (xs:List[X], f:X=>Boolean) : List[X] = xs match
case Nil => Nil
case y::ys if f (y) => y :: filter (ys, f)
case _::ys => filter (ys, f)
val zs = (0 to 7).toList
filter(zs, ((_:Int) % 3 != 0))
filterzs.filter (z => z % 3 != 0) // shorter: zs.filter(_ % 3 != 0)
zs.filter (z => z % 3 != 0).map (z => "0x%02x".format(z))
for z <- zs; if z % 3 != 0 yield z
for z <- zs; if z % 3 != 0 yield "0x%02x".format(z)
Revisit the copy operation
def copy [X] (xs:List[List[X]]) : List[List[X]] = xs match
case Nil => Nil
case y::ys => y :: copy (ys)
val xss = List(List(11,21,31),List(),List(41,51))
copy(xss)
res1: List(List(11,21,31),List(),List(41,51))
Create a copy with a flat structure: replace :: with :::
def flatten [X] (xs:List[List[X]]) : List[X] = xs match
case Nil => Nil
case y::ys => y ::: flatten (ys)
val xss = List(List(11,21,31),List(),List(41,51))
flatten(xss)
res1: List(11,21,31,41,51)
Revisit method map
def map [X,Y] (xs:List[X], f:X=>List[Y]) : List[List[Y]] = xs match
case Nil => Nil
case y::ys => f(y) :: map (ys, f)
val as = List(3,0,2)
map (as, (x:Int) => (1 to x).toList)
res1: List(List(1,2,3), List(), List(1,2))
Create a transformed list with a flat structure: replace :: with :::
def flatMap [X,Y] (xs:List[X], f:X=>List[Y]) : List[Y] = xs match
case Nil => Nil
case y::ys => f(y) ::: flatMap (ys, f)
val as = List(3,0,2)
flatMap(as, (x:Int) => (1 to x).toList)
res1: List(1,2,3,1,2):::Nil
Argument and return types of map and flatMap
map: (List[X],X=>List[Y]) => List[List[Y]]
List[Y]xsflatMap: (List[X],X=>List[Y]) => List[Y]
YList[Y]flatMapxss.flatMap (x=>x) // same as xss.flatten
for xs <- xss; x <- xs yield x
Multiple iterators
val xss = List(List(11,21,31),List(),List(41,51))
for xs <- xss; x <- xs yield (x, xs.length)
res1: List[(Int, Int)] = List((11,3), (21,3), (31,3), (41,2), (51,2))
Cross product of independent iterators
val xs = List(11,21,31)
val ys = List("a","b")
for x <- xs; y <- ys yield (x, y)
res1: List[(Int, String)] = List((11,a), (11,b), (21,a), (21,b), (31,a), (31,b))
(for x <- (1 to 7);
y <- (1 to 9) yield (x, y)).length
res1: Int = 63
val xs = List(11,21,31)
val ys = List("a","b")
for x <- xs;
y <- ys yield (x, y)
xs : List[Int]ys : List[String]x : Int
y : String
yield provides the type for the result(x, y) : (Int, String)
for ... yield (x, y) : List[(Int, String)]
foreach, map, etc. as argument