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)
What does this concept mean?
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
The way we did not provide the third argument value. The syntax
_:Intmeans I am not providing the third value which is of type
partialSum2ArgumentsProvideddid not return any value but a function
partialSum2ArgumentsProvided is a partially applied function since we did not provide all the values required by
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
Remember when we created
partialSum2ArgumentsProvided we applied arguments
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"
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
email@example.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("firstname.lastname@example.org", _:String) emailCustomerSupport: String => Unit scala> emailCustomerSupport("email@example.com")