[go: up one dir, main page]

DEV Community

Cover image for Partial Functions in Scala
Bartosz Gajda
Bartosz Gajda

Posted on • Edited on • Originally published at bartoszgajda.com

Partial Functions in Scala

Writing functions and methods that process the input data and produce some output is the very core of any type of programming. When diving deeper into different types of functions in Scala, there is one type that differs from others — partial function. As the element of Scala’s standard library, it is appropriate to know what it is and where it should be used. Let’s dive in!

What is Partial Function?

A partial function of type PartialFunction[A, B] is a unary function where the domain does not necessarily include all values of type A.
Scala Standard Library

The definition above, taken straight from the Scala lang standard library docs may seem quite obfuscated. Fear not though, as the concept of partial function is very easy to understand.

In essence, a partial function is a function that accepts only a specific set of data as the input. This doesn’t mean that the function takes only integers and not strings — this behaviour is a standard element of any function. The partial function that accepts integer parameter as the input, can specify what exact integers are accepted.

To better understand the concept, let’s see some code examples.

How to write Partial Function

First, let’s write a standard function that accepts any input of type Int:

   val standardFunction = (x: Int) => x % 10

The standardFunction is like any other - takes a parameter and returns the remainder when dividing by 10. Now, what if a developer passes zero as the parameter? Or if we need even more refined restrictions regarding the parameter? One way would be to write a long block of ifs and elses, but that is not what you would want to do. Instead, let's write a partial function, like this:

    val partialFunction: PartialFunction[Int, Int] = {
        case 1 => 100
        case 2 => 120
        case 3 => 130
      }

The partialFunction above is defined using the PartialFunction[Int, Int] trait. The type parameters say that both input and the output will be of type Int. As you can see, this function accepts only three parameters: either 1, 2 or 3. For any other parameter, an exception will be thrown.

The construction of a partial function is quite easy, but the power comes with the different operators you can use with them. Let’s look at some of them:

    partialFunction.isDefinedAt(67)

isDefinedAt() - this method allows to check if the partial function will accepts a certain parameter - in our case, 67 will not be accepted, and the method will return false.

    partialFunction.lift

lift - this method wraps the return type into an Option. For the our partialFunction, that will be Option[Int].

    partialFunction orElse otherPartialFunction

orElse - this one is very neat - it allows to chain multiple partial function, if the first one doesn't accept the input, or in different words - it's isDefinedAt method returns false.

There is plethora of other methods available — be sure to check out the official docs.

Map vs Collect

One other interesting behaviour of partial functions can be observed when using it for mapping a collection. Let’s try to use it as if it was a standard function:

    List(1, 2, 3, 4, 5).map(partialFunction)

The first three parameters are fine — the partialFunction have a defined output for them. But what happens with parameters 4 and 5. The answer is: MatchError. The map function is not able to determine the output and fails.

The solution to this is to use the collect method. This method uses the isDefinedAt method before applying the mapping function, therefore avoiding the MatchError.

    List(1, 2, 3, 4, 5).collect(partialFunction)

Summary

I hope you have found this post useful. If so, don’t hesitate to like or share this post. Additionally, you can follow me on my social media if you fancy so 🙂

Top comments (0)