Function composition builds a new function by feeding one function’s output into another’s input. Given g: A => B and f: B => C, their composition has type A => C and applies as a => f(g(a)). The type signature determines the wiring: the output type of the first function must match the input type of the second. section 2.5 section 2.7
Ordinary composition in Scala
Scala supplies compose and andThen on one-argument functions. f compose g means “run g, then f”; f andThen g expresses the same pipeline in execution order. For example, a function that subtracts an angle from Pi/2 can be composed with sin to produce cosine. section 2.5
scala> val f = (x: Double) => math.Pi / 2 - x val f: Double => Double = <function1> scala> val cos = f andThen math.sin val cos: Double => Double = <function1>
This REPL example composes two Double => Double functions with andThen. section 2.5
Composition matters because it abstracts a pattern rather than a domain. The same higher-order operation can join tiny functions or large implementations, letting programs be assembled from reusable pieces without caring about their internal size or purpose. section 2.5
Ordinary composition changes when each step produces a monadic result. A Kleisli arrow has a type such as A => F[B]. Kleisli composition joins A => F[B] to B => F[C], producing A => F[C]; it uses the monad’s sequencing rather than simply nesting ordinary function calls. section 11.4.2
def compose[A, B, C](f: A => F[B], g: B => F[C]): A => F[C]
The signature makes the intermediate monadic result and the resulting Kleisli arrow explicit. section 11.4.2
Kleisli composition gives a symmetric statement of monadic associativity: grouping three composed effectful functions either way yields the same result. Along with unit, compose can serve as a minimal basis for defining monadic operations such as flatMap. section 11.4.2
Composable stream transformations
A Pipe is a function from Stream[I] to Stream[O]. Naming transformations such as removing empty strings and lowercasing strings lets them be composed with andThen into a normalize pipe, then applied as one reusable transformation. section 15.2.2
val normalize: Pipe[String, String] = nonEmpty andThen lowerCase
Two independently defined string-stream transformations become one normalize pipe through andThen. section 15.2.2
This style separates a high-level algorithm from low-level iteration and file access. In stream processing, independently composed transformations avoid monolithic I/O loops and make variations—filtering lines, limiting input, mapping characters, or searching—easier to express. section 15.1 section 15.2.2










