Partially Applied Functions in Scala

As new to functional programming and Scala, I found it challenging to understand what Partially Applied Functions are. I decided to take it slow and let the concept sink in before I make any progress since they are some of the building blocks for writing better, cleaner functional code. And since they are used everywhere in Scala, learning them would give a better velocity when writing code.

As a new comer, I try to concentrate on following things (for any concept)

  1. What does this concept mean?

  2. What benefits does it provides? or when to use them?

With this in mind, lets start with our topic.

What does the it mean?

When we invoke/call any function, it means that we “apply” function to the arguments (used often in mathematics). In programming world it simply means calling a function with arguments. Read this stackoverflow answer for explanation.

Taking the same definition forward, "partially applied functions” means functions where some of the argument are applied. For example

scala> def sum(a:Int, b:Int, c:Int) = a + b + c
sum: (a: Int, b: Int, c: Int)Int

Invoking or calling or applying arguments to this function means

scala> sum(1,2,3)
res0: Int = 6

So how partially applied functions would look like?

scala> val partialSum2ArgumentsProvided = sum(1, 2, _:Int)
partialSum2ArgumentsProvided: Int => Int = <function1>

There are two important things to observe here

  1. The way we did not provide the third argument value. The syntax _:Int means I am not providing the third value which is of type Int

  2. The function partialSum2ArgumentsProvided did not return any value but a function

Here partialSum2ArgumentsProvided is a partially applied function since we did not provide all the values required by sum

There are other uses of _ just in case you are curious but for the purposes of this example, all it means that I do not provide the value when I apply function.

<function1> represents a Scala trait which basically means "a function of 1 parameter."

With this in mind, let’s recap.

partialSum2ArgumentsProvided is a partially applied function because we did not provide third parameter value.

So how do I get the value out of that function?

scala> partialSum2ArgumentsProvided(3)
res1: Int = 6

Aha!, so when we called/applied 3 to our partially applied function and we got our result 6 back. But how come it knows about 1 and 2?

Remember when we created partialSum2ArgumentsProvided we applied arguments 1 and 2?

It may be confusing, but try some other examples so that you can understand it.

Taking this concept even further, you may want to ignore some or all of the arguments. Lets see how

scala> val partialSum1ArgumentsProvided = sum(1, _:Int, _:Int)
partialSum1ArgumentsProvided: (Int, Int) => Int = <function2>

scala> partialSum1ArgumentsProvided(2,3)
res2: Int = 6

<function2> means "function with 2 parameters"

and

scala> val partialSumNoArgumentsProvided = sum(_:Int, _:Int, _:Int)
partialSumNoArgumentsProvided: (Int, Int, Int) => Int = <function3>

scala> partialSumNoArgumentsProvided(1,2,3)
res3: Int = 6

<function3> means "function with 3 parameters"

When to use them?

While reading over from many places following list was common

Creating a function which is pre-loaded with some values

For example, consider multiply function which looks like

scala> def multiply(a:Int, b:Int) = a * b
multiply: (a: Int, b: Int)Int

Some partially applied functions that we could make are

scala> def multiplyBy2 = multiply(_:Int, 2)
multiplyBy2: Int => Int

scala> multiplyBy2(2)
res4: Int = 4

scala> multiplyBy2(10)
res5: Int = 20

scala> def multiplyBy3 = multiply(_:Int, 3)
multiplyBy3: Int => Int

scala> multiplyBy3(10)
res6: Int = 30

scala> multiplyBy3(30)
res7: Int = 90
Providing only unique variables to a function

Consider an application that send email to customer support customersupport@enterprise.com. We may have a function that looks like

scala> def email(to:String, from:String) = ()
email: (to: String, from: String)Unit

We have not implemented how this would be done since this is just an example.

So instead of customer knowing the email for customer support or enterting it (assuming the email for support would not change), we can have a partially applied function that looks like

scala> def emailCustomerSupport = email("customersupport@enterprise.com", _:String)
emailCustomerSupport: String => Unit

scala> emailCustomerSupport("sadcustomer@googlemail.com")
comments powered by Disqus