What you'll learn
Kotlin isn't a purely functional language, but it embraces functional ideas that make code safer and clearer — immutability, pure functions, and composition. This module ties them together and points to the Arrow library for going further.
By the end you'll be able to:
- Write pure functions and prefer immutable data
- Compose functions
- Use
PairandTriple - Know what the Arrow library offers
Immutability & purity
A pure function returns the same output for the same input and has no side effects (it doesn't change anything outside itself). Combined with immutable data — Kotlin's val, read-only collections, and data class + copy() — pure functions make code dramatically easier to reason about and test:
// a PURE function: same input -> same output, no side effects
fun add(a: Int, b: Int) = a + b
// prefer immutable data + transformations over mutation
val original = listOf(1, 2, 3)
val doubled = original.map { it * 2 } // a NEW list; original untouched
println(original) // [1, 2, 3]
println(doubled) // [2, 4, 6]Key idea
map/filter. Instead of editing an object, make a copy(). Immutable-plus-pure is the safest foundation for concurrent code (Phase 6).Function composition
Because functions are values (Module 8), you can compose them — build complex behaviour by combining simple functions. Small, pure functions that compose are the essence of functional style:
val addOne = { x: Int -> x + 1 }
val double = { x: Int -> x * 2 }
// compose two functions into a new one
val addThenDouble = { x: Int -> double(addOne(x)) }
println(addThenDouble(5)) // (5 + 1) * 2 = 12Pair & Triple
For quickly grouping two or three values without defining a class, use Pair and Triple. They're destructurable (Module 25) and great for returning multiple values:
val pair = "Sara" to 25 // a Pair<String, Int>
val (name, age) = pair
println("$name, $age")
val point = Triple(1, 2, 3)
println(point.first + point.second + point.third) // 6Note
Pair/Triple for quick, local groupings. For anything that lives beyond a function or has meaning, prefer a named data class — Person(name, age) is far clearer than an anonymous Pair<String, Int>.The Arrow library
For serious functional programming, the Arrow library adds types Kotlin's standard library doesn't: Either<Error, Value> for typed error handling without exceptions, Option<T> for a richer "value or nothing," and tools for composition and validation:
// The Arrow library adds functional types like Either<Error, Value>
// for typed error handling without exceptions:
fun divide(a: Int, b: Int): Either<String, Int> =
if (b == 0) "Cannot divide by zero".left()
else (a / b).right()
// Option<T> models "a value or nothing" more richly than a plain null.Note
Result, sealed classes, and null safety. But if you love functional programming, Arrow brings the full toolkit to Kotlin.Recap & quick check
Key takeaways
- A pure function has no side effects and returns the same output for the same input.
- Prefer immutable data and transformation (map/copy) over mutation — the safest foundation, especially for concurrency.
- Functions are values, so you can compose them from small, pure pieces.
- Pair and Triple group a few values quickly; prefer a named data class for anything meaningful.
- The Arrow library adds Either, Option, and more for advanced functional programming (optional).
Quick check
1. What makes a function 'pure'?
2. What's the functional way to 'change' data?
3. Why can you compose functions in Kotlin?
4. When should you prefer a data class over a Pair?
5. What does the Arrow library add?
Excellent — you've completed Phase 5! You command Kotlin's advanced features — operators, DSLs, error handling, and functional style. Next comes the big one: Phase 6 — Coroutines & Asynchronous Programming.