kotlinintermediate

Higher-Order Functions and Lambda Patterns

Compose behavior with higher-order functions: function types, lambda receivers, and functional composition.

kotlin
// 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.