## 1. Introduction

We can think of function composition as the application of several functions, one after the other, to one or more values.

In this tutorial, we’re going to see two ways to use function composition in Scala. We’ll start with a theoretical definition of composition and then see how to implement it.

## 2. What’s Function Composition

Before diving into function composition in Scala, let’s look at a bit of math and define function composition.

**Given two functions, f: X -> Y and g: Y -> Z, we can define their composition as a function h = g ∘ f : X -> Z, where h(x) = g(f(x)).** In other words,

*h*is a function that maps elements of the domain

*X*in the codomain

*Z*. It takes

*f*to map an element of

*X*into one of

*Y*, which is the domain of

*g*. It then takes

*g*to obtain an element of

*Z*.

There are many ways to read the notation *g **∘ f*. The most common are “*g* composed with *f*” and “*f* then *g*“.

Function composition has some nice properties. Namely, **function composition is always associative: f ∘ (g ∘ h) = (f ∘ g) ∘ h.**

**Commutativity, on the other hand, is a property attained only by particular functions, and often in special circumstances.** For example, *f(x) = x ^ 2* and *g(x) = x ^ 3* commute, as *f(g(x)) = g(f(x)) = x ^ 6*. On the other hand, *f(x) = x + 3* and *g(x) = |x|* (absolute value of *x*) only commute when *x >= 0*.

## 3. Composing Functions in Scala

**In Scala, the trait Function1[T1, R] defines methods to compose functions.**

*Function1*models unary functions, that is, functions with a single parameter (

*T1*in the

*trait*definition), producing a value of type

*R*.

**There are two ways to compose such functions, according to Function1: compose and andThen. **The difference between the two relies on the order of application. Given two unary functions

*f*and

*g*,

*f andThen g*applies first

*f*and then

*g*. On the contrary, f

*compose g*applies first

*g*and then

*f*.

### 3.1. *andThen*

Let’s see how *Function1[T1, R]* defines *andThen*:

`def andThen[A](g: R => A): T1 => A = { x => g(apply(x)) }`

*andThen* inputs a *Function1[R, A]*, that is a function from *R* to a new type *A*. The result is a function from *T1* to *A*: this means that, given *f: Function1[T1, R]* and *g: Function1[R,* *A],* *f.andThen(g)* produces a function with the same domain of *f*, *T1,* and the codomain of *g*, *A*.

Let’s see an example:

```
val f = (x: Float) => x.abs
val g = (x: Float) => x + 3
val h1 = f andThen g
val h2 = g andThen f
assert(h1(-1) == 4f)
assert(h2(-1) == 2f)
```

The example above shows that the two functions are applied in a different order. *h1(-1)* is equivalent to *g(f(-1))*, which is equal to *4*. *h2(-1)*, on the other hand, is equivalent to *f(g(-1))*, which is equal to *2*.

### 3.2. *compose*

Let’s see how *Function1[T1, R]* defines *compose*:

`def compose[A](g: A => T1): A => R = { x => apply(g(x)) }`

** compose inputs a Function1[A, T1], that is a function from a new type A to T1. The result is a function from A to R: this means that given f: Function1[T1, R] and g: Function1[A, T1], f.compose(g) produces a function with the same domain of g, A, and the codomain of f, R.** In other words, this is the opposite of

*andThen*.

Let’s see an example:

```
val f = (x: Float) => x.abs
val g = (x: Float) => x + 3
val h1 = f compose g
val h2 = g compose f
assert(h1(-1) == 2f)
assert(h2(-1) == 4f)
```

**The example above shows that compose behaves with a different order of application than andThen.**

*h1(-1)*is now the same as

*f(g(-1))*, which is equal to

*2*. On the other hand,

*h2(-1)*is equivalent to

*g(f(-1))*, which returns

*4*.

### 3.3. Composing Functions With More Than One Parameter

So far we’ve seen function composition applied on unary functions. It’s now time to see how we can extend this concept to other types of functions, such as binary ones (two parameters instead of one).

**Scala models binary functions using the Function2[T1, T2, R] trait, where T1 and T2 are the types of the parameters and R is, as before, the type of the returned valued.** However,

*Function2*does not define either

*andThen*or

*compose*.

Still, *Function2* defines a method named *tupled*:

```
def tupled: Tuple2[T1, T2] => R = {
case Tuple2(x1, x2) => apply(x1, x2)
}
```

** tupled basically turns a function of type T1 => T2 => R into a function of type (T1, T2) => R. In other words, instead of inputting two separate arguments (one for T1 and one for T2), the new function inputs a single argument, which is a tuple of two elements (a Tuple2, in Scala).** This way we can get a unary function out of a binary one. Hence, we can easily use function composition as we saw before:

```
val f = (x: Int, y: Int) => (x + 1, y + 2)
val g = (x: Int, y: Int) => x - y
val h = f.tupled andThen g.tupled
assert(h((5, 4)) == 0)
```

In the example above *f* is a binary function that returns a pair. Even if *f* returns two numbers, from Scala’s point of view that is a single value of type *Tuple2[Int, Int]*. *g* is also a binary function, so we cannot compose them as-is. Instead, we have to call *tupled* on both of them. We can think of *f.tupled* and *g**.tupled* in the following way:

```
val ftupl = (t: (Int, Int)) => (t._1 + 1, t._2 + 2)
val gtupl = (t: (Int, Int) ) => t._1 - t._2
```

The types and the bodies are a little more complex to read, but they are equivalent to *f* and *g*, respectively. Still, *ftupl* and *gtupl* are unary functions, and hence we can call *andThen* on them and define *h*.

**If we had a single binary function (either f or g), we could apply the same mechanism.** Let’s see an example:

```
val f1 = (x: Int, y: Int) => x + y
val g1 = (x: Int) => x + 1
val h1 = f1.tupled andThen g1
assert(h1((5, 4)) == 10)
val f2 = (x: Int) => (x + 1, x - 1)
val g2 = (x: Int, y: Int) => x * y
val h2 = f2 andThen g2.tupled
assert(h2(2) == 3)
```

In the example above, only *f1* and *g2* are binary functions, whereas *g1* and *f2* are unary ones. In this case, we can apply *tupled* only where the arguments are more than one.

## 4. Conclusion

In this tutorial, we saw how to use function composition in Scala. Starting from the mathematical definition, we looked into *Function1*, representing unary functions in Scala, and saw how the standard library defines *compose* and *andThen*, and to use them. We also extended the concept to binary functions.

As usual, you can find the code over on GitHub.