ProAndroidDev

The latest posts from Android Professionals and Google Developer Experts.

Follow publication

Evolving with Kotlin — Advanced Functional Programming Techniques

Nirbhay Pherwani
ProAndroidDev
Published in
16 min readOct 27, 2023
Evolving with Kotlin — This image was created with the assistance of DALL·E 3

Introduction

Kotlin’s Functional Foundation

1. Immutable Data Structures

val readOnlyList = listOf("a", "b", "c")
data class Order(val orderId: Int, val product: String, val price: Double)

// Suppose we fetch this from a database or an API
val userOrders: List<Order> = fetchOrdersFromDatabase()

// If we later want to give a discount, instead of modifying the original list,
// we create a new list with updated prices.
val discountedOrders = userOrders.map { order ->
if (order.price > 100.0) {
order.copy(price = order.price * 0.9) // 10% discount
} else {
order
}
}

2. First Class Functions

fun greet(name: String) = "Hello, $name!"
val greetingFunction: (String) -> String = ::greet
println(greetingFunction("Bob")) // Outputs: Hello, Bob!
fun blur(image: Image): Image = ...
fun sharpen(image: Image): Image = ...
fun invertColors(image: Image): Image = ...

val effects = listOf(::blur, ::sharpen, ::invertColors)

// Apply all effects on an image sequentially
val processedImage = effects.fold(originalImage) { img, effect -> effect(img) }

Advanced Collection Functions

Photo by Karoline Stk on Unsplash

1. Transformations with map and flatMap

val numbers = listOf(1, 2, 3)
val squared = numbers.map { it * it } // [1, 4, 9]
val potentialUrls = listOf("https://example.com/page", "invalid-url", "https://another-example.com/resource")

val domains = potentialUrls.flatMap { url ->
runCatching { URL(url).host }.getOrNull()?.let { listOf(it) } ?: emptyList()
}
// Result: ["example.com", "another-example.com"]

2. Filtering with filter and filterNot

val numbers = listOf(1, 2, 3, 4, 5)
val evens = numbers.filterNot { it % 2 == 0 } // [1, 3, 5]
data class Product(val id: Int, val price: Double, val rating: Int, val isAvailable: Boolean)

val products = fetchProducts() // Assume this fetches a list of products

val filteredProducts = products.filter { product ->
product.price in 10.0..50.0 && product.rating >= 4 && product.isAvailable
}

3. Accumulation using fold and reduce

val numbers = listOf(1, 2, 3, 4)
val sumStartingFrom10 = numbers.fold(10) { acc, number -> acc + number } // Result: 20
val words = listOf("apple", "banana", "cherry")
val concatenated = words.fold("Fruits:") { acc, word -> "$acc $word" }
// Result: "Fruits: apple banana cherry"
val numbers = listOf(1, 2, 3, 4)
val product = numbers.reduce { acc, number -> acc * number } // Result: 24
val ranges = listOf(1..5, 3..8, 6..10)
val combinedRange = ranges.reduce { acc, range -> acc.union(range) }
// Result: 1..10

4. Partitioning with groupBy and associateBy

val words = listOf("apple", "banana", "cherry")
val byLength = words.groupBy { it.length } // {5=[apple], 6=[banana, cherry]}
data class Student(val id: String, val name: String, val course: String)

val students = fetchStudents()

// Assume students contains:
// Student("101", "Alice", "Math"), Student("101", "Eve", "History"), Student("102", "Bob", "Science")

val studentsById = students.associateBy { it.id }
// The resulting map would be:
// {"101"=Student("101", "Eve", "History"), "102"=Student("102", "Bob", "Science")}

Function Composition in Kotlin

Photo by Mohit Suthar on Unsplash
fun paint(toy: Toy): Toy { /* paints the toy and returns it */ }
fun attachWheels(toy: Toy): Toy { /* attaches wheels and returns the toy */ }
fun placeSticker(toy: Toy): Toy { /* places a sticker and returns the toy */ }
infix fun <A, B, C> ((B) -> C).compose(g: (A) -> B): (A) -> C {
return { x -> this(g(x)) }
}
val completeToyProcess = ::placeSticker compose ::attachWheels compose ::paint

Example in Action —

val rawToy = Toy()
val finishedToy = completeToyProcess(rawToy)

Why is this Useful?

Anything to Watch Out For?

Currying — The Power of Incremental Decisions

Photo by Nathan Dumlao on Unsplash

Breaking It Down

In Code

fun orderCoffee(bean: String, milk: String, flavor: String): Coffee { ... }
fun orderCoffee(bean: String): (String) -> (String) -> Coffee { ... }
val arabicaOrder = orderCoffee("Arabica")
val myCoffee = arabicaOrder("Almond Milk")("Vanilla")

Why Currying Shines

Monads — The Safety Nets of Programming

Photo by Inside Weather on Unsplash

Understanding Monads

A Practical Dive

fun findUserProfile(id: Int): Optional<UserProfile> {
// Some logic to fetch profile
}
val emailOpt = findUserProfile(123).flatMap { profile -> profile.email }

Monads in the Limelight

Lazy Evaluation and Sequences — Powering Efficient Operations

Photo by Shreyak Singh on Unsplash

Understanding Lazy Evaluation

Kotlin Sequences

In Practice — Sequences vs. Lists

val numbers = listOf(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
val result = numbers.map { it * it } // squares all numbers
.filter { it % 5 == 0 } // filters all squared numbers divisible by 5
.first() // fetches the first item
println(result) // 25
val numbersSeq = numbers.asSequence()

val resultSeq = numbersSeq.map { it * it }
.filter { it % 5 == 0 }
.first()

println(resultSeq) // 25

Benefits of Lazy Evaluation with Sequences

Tail Recursion — Harnessing Kotlin for Efficient Recursion

Photo by Ruffa Jane Reyes on Unsplash

Breaking Down Recursion

Introducing Tail Recursion

Simple Example — Factorial

fun factorial(n: Int): Int {
if (n == 1) return 1
return n * factorial(n - 1)
}
fun factorial(n: Int, accumulator: Int = 1): Int {
if (n == 1) return accumulator
return factorial(n - 1, n * accumulator)
}

Why Use Tail Recursion?

Important Note

What’s Happening Behind the Scenes with Tail Recursion?

Another Note

Conclusion

Timeless — Photo by Gaurav D Lathiya on Unsplash

Closing Remarks

Free

Distraction-free reading. No ads.

Organize your knowledge with lists and highlights.

Tell your story. Find your audience.

Membership

Read member-only stories

Support writers you read most

Earn money for your writing

Listen to audio narrations

Read offline with the Medium app

Responses (8)

Write a response