Scala - Partially Applied Functions



Partially applied functions are used to fix the number of arguments to a function. So, it produces another function with a smaller number of arguments.

Partially Applied Functions

Partially applied function is a function that takes some arguments and returns another function that takes the remaining arguments. So, you can take a function with multiple parameters and fix some of those parameters. Therefore, it will produce a new function that requires fewer parameters. It will be reused and simplify code by pre-filling some arguments.

Definition

You do not provide all of the arguments that a function requires. Instead, you provide only a subset of arguments and the resulting function expects the remaining arguments.

Syntax

The syntax of a partially applied function in Scala is -

def functionName(params1: Type1, params2: Type2, ...): ReturnType = {
  // function body
}

val partiallyApplied = functionName(params1, _: Type2, ...)

Example of Partially Applied Functions

The following example shows defining and using a partially applied function in Scala programming

object Demo {
  def add(x: Int, y: Int, z: Int): Int = x + y + z

  def main(args: Array[String]): Unit = {
    val addTwo = add(2, _: Int, _: Int)
    println(addTwo(3, 4)) 
  }
}

Save the above program in Demo.scala. Use the following commands to compile and execute this program.

Command

> scalac Demo.scala
> scala Demo

Output

9

In the example, the function add takes three parameters. The partially applied function addTwo fixes the first parameter to 2 and leaves the remaining two parameters to be provided later.

Partially Applied Functions with Collections

Partially applied functions are used with collections. So, you can create concise and readable code for various operations.

Syntax

The syntax for using partially applied functions with collections is -

collection.method(partiallyAppliedFunction)

Example

Consider the example of using partially applied functions with collections in Scala programming -

object Demo {
  def multiply(factor: Int, x: Int): Int = factor * x

  def main(args: Array[String]): Unit = {
    val double = multiply(2, _: Int)
    val numbers = List(1, 2, 3, 4, 5)
    val doubledNumbers = numbers.map(double)
    println(doubledNumbers)  
  }
}

Save the above program in Demo.scala. Use the following commands to compile and execute this program.

Command

> scalac Demo.scala
> scala Demo

Output

List(2, 4, 6, 8, 10)

In the example, the function multiply takes two parameters. It double fixes the first parameter to 2. So it creates a function that doubles each element in the list.

Higher-Order Functions with Partially Applied Functions

You can also use partially applied functions with higher-order functions to create more specialized and reusable functions.

Syntax

The syntax for using partially applied functions with higher-order functions is -

higherOrderFunction(partiallyAppliedFunction)

Example

Consider the example of using partially applied functions with higher-order functions in Scala programming -

object Demo {
  def add(x: Int, y: Int): Int = x + y

  def main(args: Array[String]): Unit = {
    val addFive = add(5, _: Int)
    val numbers = List(1, 2, 3, 4, 5)
    val result = numbers.map(addFive)
    println(result) 
  }
}

Save the above program in Demo.scala. Use the following commands to compile and execute this program.

Command

> scalac Demo.scala
> scala Demo

Output

List(6, 7, 8, 9, 10)

In the example, the function add takes two parameters. It addFive fixes the first parameter to 5. So it creates a function that adds 5 to each element in the list.

Currying vs Partially Applied Functions

Currying and partially applied functions are related concepts. But these have distinct differences. Currying transforms a function with multiple arguments into a sequence of functions with a single argument. Whereas partially applied functions fix some of the arguments of a function.

Syntax for Currying

def curriedFunction(x: Int)(y: Int): Int = x + y

Syntax for Partially Applied Functions

def functionName(x: Int, y: Int): Int = x + y
val partiallyApplied = functionName(5, _: Int)
object Demo {
  def add(x: Int)(y: Int): Int = x + y

  def main(args: Array[String]): Unit = {
    val addFive = add(5) _
    println(addFive(3)) 
  }
}

Save the above program in Demo.scala. Use the following commands to compile and execute this program.

Command

> scalac Demo.scala
> scala Demo

Output

8

In the example, the curried function add is partially applied to create a new function addFive.

Partially Applied Functions with Default Parameters

Functions can have default parameters. It can be combined with partially applied functions for more flexibility.

Syntax

The syntax for partially applied functions with default parameters -

def functionName(x: Int = 1, y: Int): Int = x + y
val partiallyApplied = functionName(_: Int)

Example

Consider the example of partially applied functions with default parameters in Scala programming -

object Demo {
  def add(x: Int = 2, y: Int): Int = x + y

  def main(args: Array[String]): Unit = {
    val addDefault = (y: Int) => add(x = 2, y = y)
    println(addDefault(3))  
  }
}

Save the above program in Demo.scala. Use the following commands to compile and execute this program.

Command

> scalac Demo.scala
> scala Demo

Output

5

In the example, the function add has a default parameter for x. The partially applied function addDefault leaves the y parameter to be provided later.

Partially Applied Functions with Variable Arguments

You can use partially applied functions with variable arguments. So you can handle functions that take a variable number of parameters.

Syntax

The syntax for partially applied functions with variable arguments is -

def functionName(params: Int*): ReturnType = {
  // function body
}

val partiallyApplied = functionName(_: _*)

Example

Consider the example of partially applied functions with variable arguments in Scala programming -

object Demo {
  def sum(nums: Int*): Int = nums.sum

  def main(args: Array[String]): Unit = {
    val addFiveAndSum: Seq[Int] => Int = (nums: Seq[Int]) => sum(5 +: nums: _*)
    println(addFiveAndSum(Seq(1, 2, 3))) 
  }
}

Save the above program in Demo.scala. Use the following commands to compile and execute this program.

Command

> scalac Demo.scala
> scala Demo

Output

11

In the example, the function sum takes a variable number of parameters. The partially applied function addFiveAndSum fixes the first parameter to 5. Additional parameters to be provided later.

Partially Applied Functions with Anonymous Functions

You can use partially applied functions combined with anonymous functions to create concise and flexible code.

Syntax

The syntax for combining partially applied functions with anonymous functions is -

val partiallyApplied = (params1: Type1, params2: Type2) => functionName(params1, _: Type2)

Example

Consider the example of combining partially applied functions with anonymous functions in Scala programming -

object Demo {
  def multiply(x: Int, y: Int): Int = x * y

  def main(args: Array[String]): Unit = {
    val double = (x: Int) => multiply(2, x)
    println(double(5)) 
  }
}

Save the above program in Demo.scala. Use the following commands to compile and execute this program.

Command

> scalac Demo.scala
> scala Demo

Output

10

In the example, the function multiply is partially applied within an anonymous function. It creates a new function double that multiplies its input by 2.

Partially Applied Functions Summary

  • You can fix a subset of a function parameters. So, it produces a new function that expects the remaining parameters.
  • This enhances code reusability, readability, and flexibility with filling arguments and creating specialized functions.
  • Partially applied functions are used with collections, higher-order functions, and variable arguments.
  • These functions can be combined with anonymous functions, default parameters, and curried functions for concise code.
  • You can use this function in various contexts, like in higher-order functions, for creating callbacks, and for functional composition.
Advertisements