Functional Programming in Kotlin - Higher-Order Functions

Functional Programming in Kotlin - Higher-Order Functions

In the previous part, we learned about the basics of functional programming and why it's beneficial to use it. In this part, we will dive deeper into the concepts that will allow you to use functional programming in Kotlin.

Let's start with the Higher-Order Functions

Higher-Order Functions

In Kotlin, functions are first-class citizens, which means we can use them just like any other value. We can pass functions as arguments to other functions, return functions from functions, and even store functions in variables. The functions that can receive a function as an arugment are called high-order functions.

Here's an example of a higher-order function:

fun performOperation(x: Int, y: Int, operation: (Int, Int) -> Int): Int {
    return operation(x, y)
}

fun add(x: Int, y: Int) = x + y

val result = performOperation(10, 5, ::add)
println(result) // Output: 15

In this example, we define a function performOperation that takes two integer arguments x and y, and a third argument operation which is a function that takes two integers and returns an integer. The performOperation function applies the operation function to x and y and returns the result.

We also define a function add that takes two integers and returns their sum. Finally, we call performOperation with 10, 5, and a reference to the add function using the double colons syntax ::add.

How to use a function

In Kotlin, there are several ways to define and use functions, including lambda functions, anonymous functions, and function references. While all three of these options allow you to pass functions as arguments and return values, they differ in syntax and behavior.

Lambda functions

Lambda functions are defined using the "->" syntax and are commonly used in functional programming to create higher-order functions. For example, consider the following code:

val numbers = listOf(1, 2, 3, 4, 5)

val sum = numbers.reduce { acc, i -> acc + i }

println(sum) // Output: 15

For more info about Lambda functions you can head to the official documentation

Anonymous Functions

Anonymous functions are another way to define functions in Kotlin. They are similar to lambda functions, but they use the fun keyword instead of the -> syntax. For example:

val numbers = listOf(1, 2, 3, 4, 5)

val sum = numbers.reduce(fun(acc, i): Int {
    return acc + i
})

println(sum) // Output: 15

Here, we define an anonymous function as the argument to reduce. The anonymous function takes the same arguments and returns the same result as the lambda function in the previous example, but it has a more verbose syntax.

With the anonymous function you can specify the type of the returned value, something that you cannot do with the lambda functions, as this will be deduced by the type inference.

Lambda expressions and anonymous functions differ in their behavior of non-local returns. If we use the return statement without a label, it will always return from the function declared with the fun keyword. This means that if we use return inside a lambda expression, it will return from the enclosing function. However, if we use return inside an anonymous function, it will return from the anonymous function itself.

Function References

Finally, function references allow you to refer to an existing function by name, without having to define a new function. For example:

fun sum(a: Int, b: Int) = a + b

val numbers = listOf(1, 2, 3, 4, 5)

val totalSum = numbers.fold(0, ::sum)

println(totalSum) // Output: 15

In this example, we define a function sum that takes two integers and returns their sum. Then, we use the :: syntax to pass the function reference to the fold function, which applies it to each element of the list.

Wrapping up

In summary, lambda functions, anonymous functions, and function references all allow you to define and pass functions as arguments in Kotlin. Lambda functions are the most concise and commonly used option for higher-order functions, while anonymous functions provide a more verbose syntax. Function references allow you to refer to existing functions by name, without having to define new functions.

See you next time!