liveBook · Manning

Composition

As explained in Functional Programming in Scala, Second Edition

Kleisli composition is an operation that composes functions producing monadic results into a larger monadic computation.

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

How Functional Programming in Scala, Second Edition covers it

How deep it goes
Defines ordinary composition by types and implementation, then derives Kleisli composition as a view of monadic associativity.
Examples
Uses trigonometric functions, Option cases, and composed nonempty and lowercase stream pipes.
What it assumes
Introduces composition through function types before relying on monads and stream transformations.
What you can do after
Build it from scratch by implementing ordinary and Kleisli compose, then combine stream transformations.
How it connects
Connects higher-order functions, parametric polymorphism, monads, flatMap, associativity, streams, and Pipe.

Also explained in

Compare how 11 books explain composition →

Related concepts

This explainer was generated by Manning's knowledge graph from the text of Functional Programming in Scala, Second Edition. The section links point to the parts of the book it draws on.