This is the second part of the functional programming series. If you have missed the previous one, start here.
Series pit stops
- f(1) — Basics, Understanding Functions
- f(2) — Functions in Kotlin, Pure functions (you are here)
- f(3) — Function composition
- f(4) – Currying function
In this pit stop, we’ll take a brief look at how we write or represent a function in Kotlin. As a language what functional operations does Kotlin provide us out of the box? We’ll also see about pure functions.
Pre-requisites
- Basic programming knowledge
- School mathematics
- Previous pit stop
Functions in Kotlin
As I presume that you already know that in Kotlin we define the function using the fun keyword. I also guess you have played the Kotlin drinking game - drink a shot each time when someone says fun in a Kotlin talk 😛
Jokes apart, Let’s take a look at some of the common functional operations on lists that Kotlin provides out of the box which we may have used in our everyday dev chores without actually realising or comparing it with functional paradigms.
Some of you may know the following functions, but the idea is to provide a different perspective on them when represented mathematically and to digest the functional concepts that we absorbed from the previous pit stop.
Dissecting map()
We would have used map frequently on lists in Kotlin. Usually mapping the list of items we receive from an API call to the view data. Let’s connect the dots with the knowledge we consumed from our previous pit stop.
Representation of map
map(f: (A) -> B): List<B>
KotlinA functional instance, that takes in a function as an argument and applies to all the elements present in the list of A and provides us with the list of B
Mathematically:
let set of A = { 1, 2, 3, 4, 5, 6 }
given f(x) = x + 1
map(f: (A) -> B) gives,
f1: (1) -> 1 + 1 = 2
f2: (2) -> 2 + 1 = 3
...
Programatically:
val listA = listOf(1, 2, 3, 4, 5, 6)
val listB = listA.map { x -> x + 1 } //print
// output = [2, 3, 4, 5, 6, 7]
KotlinFun Fact: When we say map takes a function as an argument, it’s actual representation is map({ x -> x + 1}). But in Kotlin, if the last argument is a function, we can remove the enclosing function brackets. That’s why we have map { x -> x + 1 }
Dissecting groupBy()
When we need to group or arrange our lists or mapped to one item, we use groupBy Representation of groupBy
groupBy(g: (C) -> D): Map<D, List<C>>
KotlinA functional instance, that takes in a function from C to D as an argument, applies the function to all the elements present in the list and returns a key value pair of list where the key being the type D and values of type C.
Mathematically:
let set of C= { 1, 2, 3, 4, 5, 6 }
given f(x) = x + 1
groupBy(f: (C) -> D) gives,
f1: (1) -> 1 + 1 = 2 and returns 2=[1] //key value pairs
f2: (2) -> 2 + 1 = 3 and returns 3=[2]
...
Programatically:
val listC = listOf(1, 2, 3, 4, 5, 6)
val listD = listC.groupBy { x -> x + 1 } //print
// output = {2=[1], 3=[2], 4=[3], 5=[4], 6=[5], 7=[6]}
KotlinDissecting reduce()
We use this operation if we need to reduce the list into a single value. Representation of reduce
reduce(f: (E,E) -> E): E
KotlinA functional instance, that takes in a function by the operation (E, E) -> E, to reduce the list to a single value
Mathematically:
let set of E= { 1, 2, 3, 4, 5, 6 }
given f(x1, x2) = x1 + x2 // simply adding all the elements in E
reduce(f: (E, E) -> E) gives,
f1: (1, 2) -> 1 + 2 = 3 // which is x1 for f2
f2: (3, 3) -> 3 + 3 = 6 // which is x1 for f3
Programatically:
val listE = listOf(1, 2, 3, 4, 5, 6)
val sumOfE = listE.reduce { first, second -> first + second }
// output = 21
KotlinPure Functions
If you recall, we kept mentioning multiple times that in order to make a function safe with less or no bugs, the function must be a pure function.
A function is considered as pure if it satisfies the following conditions (to put in a simple terms)
- The function must always return a value
- It must not throw exceptions or errors
- It must not mutate or change anything outside the scope of the function. The changes within the function must also not be visible outside
- It should not mutate or change its argument
- For a given set of arguments, it should always return the same value
A function which does not satisfy the above conditions is called impure functions (We also have the partial function, currently out of scope for this post)
For better understanding, let’s analyse and classify the following functions as pure and impure
Example 1
fun division(x: double, y: Double): Double = x / y
KotlinThe above function is pure as (let’s not consider overflow at the moment)
- Returns value ✅
- No mutation of argument or external dependencies ✅
- always returns the same value for x and y ✅
- No exceptions or errors (Divided by 0 is infinity, an instance of Double) ✅
Example 2
fun addItems(value: Int, list: MutableList<Int>): List<Int> {
list.add(value)
return list
}
KotlinThe above functions is impure as
- Mutates the argument and the mutation is visible ❌
Summary
- We represented some of the common functions on list mathematically to gain more clarity of what we use in our everyday chores
- map() : A functional instance, that takes in a function as an argument and applies to all the elements present in the list of A and provides us with the list of B
- groupBy() : A functional instance, that takes in a function from C to D as an argument, applies the function to all the elements present in the list and returns a key-value pair of the list where the key being the type D and values of type C.
- reduce() : A functional instance, that takes in a function by the operation (E, E) -> E, to reduce the list to a single value
- A function is considered as safe, easily testable and less or no bugs if it’s pure. Pure functions always returns value, does not mutate its argument, always return the same result for the given parameters and should not throw exceptions
Additional References
If you think you have learned something new or if you like this series or you want to boost my morale to publish the next pit stop fast, please share the post
Thanks a lot for reading this article. Stay tuned!!