โ† back to index

Kleisli Categories

Bartosz Milewski ยท 2014 ยท Category Theory for Programmers, Ch. 4

Prereqs: ๐Ÿž Chapter 1 (Category), ๐Ÿž Chapter 2 (Types and Functions). 7 min.

Side effects are not side effects if you make them part of the return type. A Kleisli category redefines morphisms as functions a โ†’ m(b) and composition as the fish operator (>=>). The category laws still hold. You get purity and logging (or failure, or nondeterminism) at the same time.

a b f a M(b) f plain morphism Kleisli arrow
a M(b) M(c) f g g ▷ f (fish)

The problem: composing embellished functions

You have functions that return a value plus a log string. You can't compose them with ordinary function composition because the types don't line up: a โ†’ (b, string) followed by b โ†’ (c, string) needs someone to unpack the pair and concatenate the logs. That "someone" is Kleisli composition.

Scheme

The Writer type and Kleisli composition

The Writer type wraps a value with a log: (value . log). Kleisli composition (>=>, the "fish operator") extracts the value from the first function's result, feeds it to the second, and concatenates the logs.

Scheme

Identity and the category laws

Every category needs an identity morphism. In the Kleisli category for Writer, identity returns the value unchanged and contributes an empty log. Identity and fish together let us check the three category laws: left identity, right identity, and associativity.

Scheme

Logging as a real use case

The Writer monad lets you add logging to pure functions. Each function declares what it logs in its return type. Composition handles the plumbing. No mutable state. No side effects. Just functions and types.

Scheme

Beyond Writer: the Kleisli pattern

Writer is just one Kleisli category. Replace (value . log) with (value | nothing) and you get the Maybe/Optional monad for partial functions. Replace it with a list and you get nondeterminism. The recipe is the same each time: define a type embellishment, a composition rule, and an identity. If the laws hold, you have a Kleisli category.

Scheme

Notation reference

Blog / Haskell Scheme Meaning
Writer a = (a, String)(cons val log)Value paired with log
(>=>) :: (aโ†’m b) โ†’ (bโ†’m c) โ†’ (aโ†’m c)(fish f g)Kleisli composition
return :: a โ†’ m a(writer-id x)Kleisli identity
Maybe avalue | 'nothingOptional/partial result
compose m1 m2(fish f g)Same as >=>
Neighbors

Milewski chapters

Paper pages that use Kleisli categories

Foundations (Wikipedia)

Translation notes

The blog post uses C++ templates and Haskell. This page uses Scheme cons pairs as the Writer type and a plain fish function for Kleisli composition. Logs accumulate via list append, but the construction works for any monoid (strings, numbers under addition, etc.) and any monad, not just Writer.

Ready for the real thing? Read the blog post. Start with the C++ examples, then try the Haskell fish operator.