Higher-Order Functions and Lambda Patterns
Compose behavior with higher-order functions: function types, lambda receivers, and functional composition.
// Function types
typealias Predicate<T> = (T) -> Boolean
typealias Transformer<T, R> = (T) -> R
typealias Reducer<T, R> = (R, T) -> R
// Higher-order function
fun <T> List<T>.customFilter(predicate: Predicate<T>): List<T> {
val result = mutableListOf<T>()
for (item in this) {
if (predicate(item)) result.add(item)
}
return result
}
// Function composition
fun <A, B, C> compose(f: (B) -> C, g: (A) -> B): (A) -> C = { a -> f(g(a)) }
fun <A, B, C> ((A) -> B).andThen(f: (B) -> C): (A) -> C = { a -> f(this(a)) }
// Pipeline builder
class Pipeline<T>(private var value: T) {
fun <R> pipe(transform: (T) -> R): Pipeline<R> = Pipeline(transform(value))
fun <R> pipeIf(condition: Boolean, transform: (T) -> R, default: (T) -> R): Pipeline<R> =
if (condition) Pipeline(transform(value)) else Pipeline(default(value))
fun result(): T = value
}
fun <T> pipeline(initial: T) = Pipeline(initial)
// Memoization
fun <T, R> memoize(fn: (T) -> R): (T) -> R {
val cache = mutableMapOf<T, R>()
return { key -> cache.getOrPut(key) { fn(key) } }
}
// Partial application
fun <A, B, R> ((A, B) -> R).partial(a: A): (B) -> R = { b -> this(a, b) }
fun <A, B, C, R> ((A, B, C) -> R).partial(a: A): (B, C) -> R = { b, c -> this(a, b, c) }
// Middleware pattern
typealias Handler = (String) -> String
typealias Middleware = (Handler) -> Handler
val loggingMiddleware: Middleware = { next ->
{ request ->
println("→ Request: $request")
val response = next(request)
println("← Response: $response")
response
}
}
val authMiddleware: Middleware = { next ->
{ request ->
if (request.contains("auth")) next(request)
else "Unauthorized"
}
}
fun applyMiddleware(handler: Handler, vararg middlewares: Middleware): Handler =
middlewares.foldRight(handler) { mw, acc -> mw(acc) }
fun main() {
// Custom filter
val nums = listOf(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
println(nums.customFilter { it % 2 == 0 }) // [2, 4, 6, 8, 10]
// Composition
val double: (Int) -> Int = { it * 2 }
val addOne: (Int) -> Int = { it + 1 }
val doubleAndAddOne = double.andThen(addOne)
println(doubleAndAddOne(5)) // 11
// Pipeline
val result = pipeline(" Hello, World! ")
.pipe { it.trim() }
.pipe { it.uppercase() }
.pipe { it.replace(",", "") }
.result()
println(result) // HELLO WORLD!
// Memoize
val slowSquare = memoize<Int, Int> { n ->
Thread.sleep(100) // simulate expensive computation
n * n
}
println(slowSquare(5)) // slow
println(slowSquare(5)) // instant (cached)
// Partial application
val add: (Int, Int) -> Int = { a, b -> a + b }
val add10 = add.partial(10)
println(add10(5)) // 15
println(add10(20)) // 30
// Middleware
val handler: Handler = { "Processed: $it" }
val app = applyMiddleware(handler, loggingMiddleware, authMiddleware)
println(app("auth:hello"))
println(app("no-auth"))
}Use Cases
- Composable transformation pipelines
- Middleware and interceptor patterns
- Functional programming abstractions
Tags
Related Snippets
Similar patterns you can reuse in the same workflow.
Collections — map, filter, groupBy, and More
Master Kotlin collections: functional transformations, aggregations, grouping, and partition operations.
Best for: Data processing and transformation pipelines
Result Monad — Functional Error Handling
Handle errors functionally with Kotlin Result: map, recover, fold, and chaining fallible operations.
Best for: Type-safe error handling without exceptions
Functional Error Handling with Either
Use Either and Option for type-safe error handling: Railway-oriented programming without exceptions.
Best for: Type-safe error handling without exceptions
Functional Error Handling with Either
Implement Either monad for type-safe error handling with map, flatMap, and fold operations.
Best for: Type-safe error handling without exceptions