Instructor: Stefan Mitsch
How to combine collection elements into an aggregate result?
Express in an imperative style
Java
int sum (List<Int> xs) { int result = 0; for (int i = 0; i < xs.length; i++) result += xs.get(i); return result; }
Scala
def sum (xs:List[Int]) : Int = var result = 0 for i <- 0 until xs.length do result = result + xs(i)
Express in a functional style
def sum (xs:List[Int]) : Int = xs match case Nil => 0 case y::ys => y + sum (ys) val xs = List(11,21,31) sum (xs)
sum(11::21::31::Nil) --> sum(11::21::31::Nil) --> 11 + sum(21::31::Nil) --> 11 + (21 + sum(31::Nil)) --> 11 + (21 + (31 + sum(Nil))) --> 11 + (21 + (31 + 0)) --> 11 + (21 + 31) --> 11 + 52 --> 63 = (11 + (21 + (31 + 0)))
With a different zero element
def sum (xs:List[Int], z:Int = 0) : Int = xs match case Nil => z case y::ys => y + sum (ys, z) val xs = List(11,21,31) sum (xs)
sum(11::21::31::Nil) --> sum(11::21::31::Nil, 0) --> 11 + sum(21::31::Nil, 0) --> 11 + (21 + sum(31::Nil, 0)) --> 11 + (21 + (31 + sum(Nil, 0))) --> 11 + (21 + (31 + 0)) --> 11 + (21 + 31) --> 11 + 52 --> 63 = (11 + (21 + (31 + 0)))
Sum of elements in a list computing forward
def sum (xs:List[Int], z:Int = 0) : Int = xs match case Nil => z case y::ys => sum (ys, z + y) val xs = List(11,21,31) sum (xs)
sum(11::21::31::Nil) --> sum(11::21::31::Nil, 0) --> sum(21::31::Nil, 11) --> sum(31::Nil, 32) --> sum(Nil, 63) --> --> --> --> 63 = (((0 + 11) + 21) + 31)
generalize the + operation
+
def sum (xs:List[Int], z:Int) : Int = xs match case Nil => z case y::ys => sum (ys, z + y) val xs = List(11,21,31) sum (xs, 0)
def foldLeft (xs:List[Int], z:Int, f:((Int,Int)=>Int)) : Int = xs match case Nil => z case y::ys => foldLeft (ys, f(z,y), f) val xs = List(11,21,31) foldLeft (xs, 0, _+_)
Change the return type
def foldLeft (xs:List[Int], z:String, f:(String,Int)=>String) : String = xs match case Nil => z case y::ys => foldLeft (ys, f(z, y), f) val xs = List(11,21,31) foldLeft (xs, "", _ + " " + _)
Changing the parameter type
def foldLeft (xs:List[List[Int]], z:Int, f:(Int,List[Int])=>Int) : Int = xs match case Nil => z case y::ys => foldLeft (ys, f(z, y), f) val xss = List(List(11,21,31),List(),List(41,51)) foldLeft (xss, 0, _ + _.length)
Abstracting the type
def foldLeft [Z,X] (xs:List[X], z:Z, f:((Z,X)=>Z)) : Z = xs match case Nil => z case y::ys => foldLeft (ys, f(z,y), f) val xs = List(11,21,31) foldLeft (xs, "!", (z:String,x:Int) => z + " " + x)
res1: String = ! 11 21 31
def foldRight [X,Z] (xs:List[X], z:Z, f:((X,Z)=>Z)) : Z = xs match case Nil => z case y::ys => f (y, foldRight (ys, z, f)) val xs = List(11,21,31) foldRight (xs, "!", (x:Int,z:String) => x + " " + z)
res1: String = 11 21 31 !
List
fold
xss.foldLeft (0) ((z,xs)=>z + xs.length)
def foldLeft [Z,X] (xs:List[X], z:Z, f:((Z,X)=>Z)) : Z = xs match { case Nil => z case y::ys => foldLeft (ys, f(z,y), f) }
def foldRight [X,Z] (xs:List[X], z:Z, f:((X,Z)=>Z)) : Z = xs match { case Nil => z case y::ys => f (y, foldRight (ys, z, f)) }
foldLeft
return foldLeft (ys, f(z, y))
f
foldRight
return f (y, foldRight (ys, z))
def foldLeft [Z,X] (xs:List[X], z:Z, f:((Z,X)=>Z)) : Z = xs match case Nil => z case y::ys => foldLeft (ys, f(z,y), f)
def foldRight [X,Z] (xs:List[X], z:Z, f:((X,Z)=>Z)) : Z = xs match case Nil => z case y::ys => f (y, foldRight (ys, z, f))
val xs = List(a, b, c) foldLeft (xs, z, f) === f( f( f(z,a),b),c) foldRight(xs, z, f) === f(a, f(b, f(c,z)))
xs.foldLeft(z)(f) xs.foldRight(z)(f) f f / \ / \ f c a f / \ / \ f b b f / \ / \ z a c z
def sum (xs: List[Int]) = xs.foldLeft(0)(_+_) def prod (xs: List[Int]) = xs.foldLeft(1)(_*_) def or (xs: List[Boolean]) = xs.foldLeft(false)(_||_) def and (xs: List[Boolean]) = xs.foldLeft(true)(_&&_) def append [X] (xs: List[X])(ys: List[X]) = xs.foldRight(ys)(_::_) def flatten [X] (xs: List[List[X]]) = xs.foldLeft(Nil:List[X])(_:::_) def length [X] (xs: List[X]) = xs.foldLeft(0)((z,x)=>z+1) def reverse [X] (xs: List[X]) = xs.foldRight(Nil:List[X])((x,zs)=>zs:::List(x)) def map [X,Y] (xs: List[X], f: X=>Y) = xs.foldRight(Nil:List[Y])(f(_)::_) def filter [X] (xs: List[X], f: X=>Boolean) = xs.foldRight(Nil:List[X])((x,zs)=>if f(x) then x::zs else zs)