Scala: Function Object to the Rescue

The Function object has been there since Scala 1.0 version. It provides some utility methods for dealing with higher-order functions. Despite the simplicity and usefulness of some of them I found that not only do many beginning developers not use it, but they don’t even know about them. In this post I would like to remind you about some of the functions I find useful in some cases.

chain

To get started let’s introduce 2 extremely simple functions from Int to Int. One of them, let’s call it inc, will increase a number by one and the other one, double, with multiply a number by 2.

1
2
scala> val inc: Int => Int = x => x + 1
scala> val double: Int => Int = x => x * 2

Note: that for the both functions we could use shorter definition form like val inc: Int => Int = _ + 1. So what do we do when there is a sequence of these functions and we want to combine them? One of the most popular option in my practice is the following:

1
scala> List(inc, double, inc) reduce (_ andThen _)

This piece of code takes a sequence of functions and combines them using andThen method starting with the first one in the list and returning resulting function from Int to Int. It is by no means bad code. Personally I like it. Let’s see how it can be simpler with using chain function from the Function object:

1
scala> Function.chain(List(inc, double, inc))

It does exactly the same as the previous snippet but it might be more intuitive for the beginning developers. If we import all the functions from Function object first it will be dead simple:

1
2
scala> import Function._
scala> chain(List(inc, double, inc))

Note: If you want to use compose instead of andThen you still can do this with chain by reversing the sequence:

1
scala> chain(List(inc, double, double).reverse)

tupled

Imagine there is a tuple of 2 elements, id and name, representing a user wrapped into Option:

1
scala> val user: Option[(Int, String)] = Some(1, "Bob")

And a function, let’s call it auth, which accepts id and name as two different arguments:

1
scala> val auth: (Int, String) => Boolean = (id, name) => id == 1 && name == "Bob"

We can’t just map the auth function over the user because the former expects 2 arguments and our user is one tuple of 2 elements. One of the options would be extracting id and name and pass them as the separate arguments to the auth function. It requires some boilerplate code to write. This is where we can use tupled function from the Function object. What it does is taking a function of let say 2 arguments and convert it to a function taking a tuple of 2 elements with the types of the initial arguments. That’s exactly what we need to map over the auth function:

1
2
scala> user map auth.tupled
res4: Option[Boolean] = Some(true)

There are tupled functions defined for tupling functions of arity from 2 to 5 inclusive. I rarely use tuples with elements more than 2 or 3 so I find it convenient.

Technically in the previous example the function tupled was called on the function itself (as it’s defined both in the Function object and Function* traits). Another “trick” that can be useful is mapping over a map in what many people would say a natural way. (Also it demonstrates using the tupled function from Function object and not defined in Function* trait). In Scala you can’t write code like this:

1
2
3
4
5
6
7
8
9
scala> val m = Map(1 -> "first", 2 -> "second")
scala> m map { (k, v) => s"$k:$v" }
<console>:12: error: missing parameter type
Note: The expected type requires a one-argument function accepting a 2-Tuple.
      Consider a pattern matching anonymous function, `{ case (k, v) =>  ... }`
              m map { (k, v) => s"$k:$v" }
                       ^
<console>:12: error: missing parameter type
              m map { (k, v) => s"$k:$v" }

What many developers would do is something like this:

1
2
scala> m map { case (k, v) => s"$k:$v" }
res5: scala.collection.immutable.Iterable[String] = List(1:first, 2:second)

You can achieve the same using the tupled function:

1
2
scala> m map tupled { (k, v) => s"$k:$v" }
res6: scala.collection.immutable.Iterable[String] = List(1:first, 2:second)

Maybe not so useful but helps to understand its application.

unlift

To illustrate the usage of unlift let’s write a function that takes an Int and returns Some(x) if x is equal or greater than zero and None otherwise:

1
scala> val f: Int => Option[Int] = Option(_) filter (_ >= 0)

What unlift function does is it turns a function A => Option[B] into a PartialFunction[A, B]. It lets us to use our function in any place where partial function is required. To make it clear that’s how our function can be used to filter out the positive integers in the list:

1
2
3
scala> import Function._
scala> List(-1,0,1) collect unlift(f)
res7: List[Int] = List(0, 1)

I don’t use this on a daily basis but there are some cases like this when it comes very handy.

Bonus: there is an opposite function defined in PartialFunction called lift. To see how it is related to unlift function the following equation is always true:

1
2
scala> f == unlift(f).lift
res8: Boolean = true

uncurried/untupled

These functions are the opposite to curried and tupled respectively. I didn’t see them used as much as the functions described above.

Although there is nothing new I found that it’s easy to forget about some useful API provided by Scala standard library. I hope this reminder is on time and can save you a couple of lines of code now or in the future.