From Java to Scala: A Higher Order

Erik Lundqvist
Binary Dreams
Published in
5 min readFeb 11, 2014

--

I have previously mentioned how functional programming lets you favour intent over step by step instructions, and now it’s time for a practical demonstration. Here are a few examples using some of the more common higher order functions used in functional programming and Scala when working with collections.

filter

def filter(p: (A) ⇒ Boolean): List[A]

It seems only natural to start with filter, after all, before we iterate over a collection we need to make sure it contains the right data. filter takes a single function as an argument, a predicate function. A predicate is a function which can be used to answer true/false questions on values of a certain type. A new collection is created containing each element which the predicate is true for.

Consider the following use case:
As a employee I want to know if it is the 25th day of the month so that I can know when I get paid.

// A payday predicate could be defined as:
def isPayday = (dayOfMonth: Int) => dayOfMonth == 25
//Now, given a List of all days of the month I would simply do:

val list = 22 to 28 toList
res0: List[Int] = List(22, 23, 24, 25, 26, 27, 28)
scala> list.filter(isPayday)
res1: List[Int] = List(25)
// Compare that to doing the same using Google’s Guava library:

public class IsPaydayPredicate implements Predicate<Integer> {
@Override
public boolean apply(Integer day) {
return 25 == day;
}
}

map

def map[B](f: (A) ⇒ B): List[B]

map applies a unary function on each element of a collection, and each result from that function is inserted into a new collection. That means if you call map on a collection with 5 elements the resulting collection will also contain 5 elements.

Consider the following use case:
As a loudmouth I want to use caps so that I can be heard.

val words = List(“can”, “you”, “hear”, “me?”)
scala> words.map((s: String) => s.toUpperCase)
res2: List[String] = List(CAN, YOU, HEAR, ME?)

flatten

def flatten[B]: List[B]

flatten collapses one level in a collection containing other collections, i.e. a List of Lists is turned into a List.

scala> val lists = List(List(1, 2, 3), List(4, 5, 6))
lists: List[List[Int]] = List(List(1, 2, 3), List(4, 5, 6))
scala> lists.flatten
res7: List[Int] = List(1, 2, 3, 4, 5, 6)

Could be used to transform input before it can be used by the consuming function when you have use case which covers the larger picture. Consider the following use case:

As a manager I want to see how much work we have planned across all projects so that I know if I have enough staff.

// Adds the points from all stories
def allPoints(stories: List[Story]): Int =
stories.foldLeft(0)(_ + _)

Notice how Scala lets you omit declaring the name of the parameters for the adding function, and how I could use a ‘_’ as a placeholder instead. We can do this as the type can be inferred and we don’t actually care about which parameter is which.

// Returns a List containing a List of Stories for each Project
def allStories(projects: List[Project]): List[List[Story]] =
projects.map((project) => project.stories)
// Flattens the List of Story Lists into a List of Stories
// before calling allPoints
val points = allPoints(allStories(projects).flatten)

flatMap

def flatMap[B](f: (A) ⇒ GenTraversableOnce[B]): List[B]

flatMap applies a function, which returns a collection, to each element of a collection and flattens the result into a new collection. Consider the following:

// Adds the points from all stories
def allPoints(stories: List[Story]): Int =
stories.foldLeft(0)(_ + _)
def allStories(projects: List[Project]): List[Story] =
projects.flatMap((project) => project.stories)
val points = allPoints(allStories(projects))

foldLeft

def foldLeft[B](z: B)(f: (B, A) => B): B

foldLeft is different from map as it takes a starting value and a binary function as parameters. For the first element in the collection the starting value is passed in as the first argument and the element itself as the second. For any remaining elements the result of the previous operation is used as the first argument. This means foldLeft produces a single result and not a new collection.

scala> val list = List(1, 2, 3)
list: List[Int] = List(1, 2, 3)
scala> list.foldLeft(0)((a, b) => a + b)
res3: Int = 6

This produces three calls the our adding function.
1. 0 + 1 // 0 is the starting value, and 1 is the 1st element.
2. 1 + 2 // 1 is the result of the previous operation, and 2 is the 2nd element.
3. 3 + 3 // 3 is the result of the previous operation, and 3 is the 3rd element.

Consider the use case with the secret agent from my tail recursion post:
As a secret agent I want to reverse the text of my documents so that I can keep them secret.

def reverseFoldLeft(s: String): String = 
s.foldLeft("")((a, b) => b + a)

// It can be shorted even further by using ```/:``` which is a // shortcut for foldLeft.

def reverseFoldLeft(s: String): String =
(""/:s)((a, b) => b + a)

foldRight

def foldRight[B](z: B)(op: ((A, B), B) ⇒ B): B

foldRight goes from right to left and swaps the order of the parameters to the binary function.

scala> val list = List(1, 2, 3)
list: List[Int] = List(1, 2, 3)
scala> list.foldRight(0)((a, b) => a + b)
res3: Int = 6

This produces three calls the our adding function.
1. 3 + 0 // 3 is the last element and 0 is the starting value.
2. 2 + 3 // 2 is the 2nd element and 3 is the result from the previous operation.
3. 1 + 5 // 1 is the 1st element and 5 is the result from the previous operation.

// Just like foldLeft there is a short hand version of 
// foldRight, :\.
def reverseFoldRight(s: String): String =
(s:\"")((a, b) => b + a)

What’s next?

This post only scratches the very surface of higher order functions and collections, and I am sure there will be more posts with more advanced content. Especially map and flatMap have a lot of interesting use cases, which I will show you when I am brave enough to look at Monads.

Next post will compare classes in Java and Scala. Until then!

--

--

Erik Lundqvist
Binary Dreams

35, Swedish, book reviewer, avid reader of fantasy/Sci-Fi/Crime, Software Developer