kotlinintermediate

Functional Composition and Pipelines

Compose functions and build transformation pipelines with Kotlin higher-order functions.

kotlin
// Function composition
infix fun <A, B, C> ((B) -> C).compose(f: (A) -> B): (A) -> C = { a -> this(f(a)) }
infix fun <A, B, C> ((A) -> B).andThen(f: (B) -> C): (A) -> C = { a -> f(this(a)) }

// Pipeline operator (like Unix pipe)
infix fun <A, B> A.pipe(f: (A) -> B): B = f(this)

// Currying
fun <A, B, C> ((A, B) -> C).curry(): (A) -> (B) -> C = { a -> { b -> this(a, b) } }

// Memoize
fun <A, R> ((A) -> R).memoize(): (A) -> R {
    val cache = mutableMapOf<A, R>()
    return { a -> cache.getOrPut(a) { this(a) } }
}

// Builder-style pipeline
class Pipeline<T>(private val value: T) {
    fun <R> map(transform: (T) -> R) = Pipeline(transform(value))
    fun <R> flatMap(transform: (T) -> Pipeline<R>) = transform(value)
    fun filter(predicate: (T) -> Boolean): Pipeline<T?> =
        Pipeline(if (predicate(value)) value else null)
    fun get() = value
}

fun <T> pipeline(value: T) = Pipeline(value)

fun main() {
    // Compose functions
    val double = { x: Int -> x * 2 }
    val addOne = { x: Int -> x + 1 }
    val square = { x: Int -> x * x }

    val doubleThenAdd = addOne compose double  // addOne(double(x))
    val addThenDouble = double compose addOne  // double(addOne(x))

    println("doubleThenAdd(5): ${doubleThenAdd(5)}")  // 11
    println("addThenDouble(5): ${addThenDouble(5)}")  // 12

    // andThen (left to right)
    val transform = double andThen addOne andThen square
    println("transform(3): ${transform(3)}")  // (3*2+1)^2 = 49

    // Pipe operator
    val result = 5 pipe double pipe addOne pipe square
    println("Piped: $result")  // 121

    // String processing pipeline
    val cleanText = { s: String -> s.trim() }
    val lowercase = { s: String -> s.lowercase() }
    val removeSpaces = { s: String -> s.replace(" ", "-") }

    val slugify = cleanText andThen lowercase andThen removeSpaces
    println("Slug: ${slugify("  Hello World  ")}")  // hello-world

    // Currying
    val add = { a: Int, b: Int -> a + b }
    val curriedAdd = add.curry()
    val add5 = curriedAdd(5)
    println("Curried add5(3): ${add5(3)}")  // 8

    // Memoized fibonacci
    lateinit var fib: (Int) -> Long
    fib = { n: Int ->
        if (n <= 1) n.toLong() else fib(n - 1) + fib(n - 2)
    }.memoize()
    println("Fib(40): ${fib(40)}")

    // Pipeline builder
    val output = pipeline("  Hello World  ")
        .map { it.trim() }
        .map { it.lowercase() }
        .map { it.replace(" ", "_") }
        .map { it.uppercase() }
        .get()
    println("Pipeline: $output")  // HELLO_WORLD
}

Use Cases

  • Data transformation pipelines
  • Reusable function composition
  • Text processing and slug generation

Tags

Related Snippets

Similar patterns you can reuse in the same workflow.