Skip to content
The Lumenary
First-year graduateGraduate 130 min

Monads

Wrap, flatten, evaluate — one shape behind free algebras, closure operators, probability kernels, sheaf resolutions and effectful programs.

Formally verified · 16 LeanComputationally tested · 2 PythonAI-drafted · awaiting human reviewMathematically reviewed: Awaiting human review
MotivationH

Formal expressions and how to evaluate them

Take a set XX and form the set TXTX of finite lists of elements of XX — formal products x1x2⋯xnx_1 x_2 \cdots x_n with no rule for multiplying yet. Three pieces of structure are already there, before any algebra is chosen:

  • every element is a one-letter word: x↦[x]x \mapsto [x];
  • a list of lists can be flattened: [[x1,x2],[ ],[x3]]↦[x1,x2,x3][[x_1, x_2], [\,], [x_3]] \mapsto [x_1, x_2, x_3];
  • a monoid MM is exactly a set with a way to evaluate words, TM→MTM \to M, compatible with the first two.

The same pattern appears far from monoids. Subsets of subsets can be flattened by union, and a complete lattice is a set where every subset can be evaluated to its supremum. Probability distributions over probability distributions can be flattened by averaging, and expectation evaluates a distribution of numbers to a number. On a topological space, Godement's "standard construction" sends a sheaf to its sheaf of discontinuous sections and builds sheaf cohomology by iterating. In a programming language, a computation that may fail, branch or print returns a value wrapped in that effect, and running two such computations in sequence requires flattening.

A monad is the common shape: a functor TT with a unit η:X→TX\eta : X \to TX and a flattening μ:TTX→TX\mu : TTX \to TX obeying associativity and unit laws. Its algebras are the structures that TT describes. This lesson develops the theory — algebras, the Kleisli and Eilenberg–Moore categories, the correspondence with adjunctions, and Beck's monadicity theorem — and then looks at the same idea through the eyes of topologists, algebraists, probabilists and computer scientists.

IntuitionH

Wrap, flatten, evaluate

Read TXTX as "XX-shaped things wrapped in a TT-structure": words in XX, subsets of XX, distributions on XX, terms built from variables in XX, computations returning an XX.

  • ηX:X→TX\eta_X : X \to TX wraps a plain element as a trivial structure: the one-letter word, the singleton, the point mass, the variable, the computation that does nothing and returns xx.
  • μX:TTX→TX\mu_X : TTX \to TX flattens two layers of structure into one: concatenation of words, union of subsets, averaging of distributions, substitution of terms into terms, running a computation that returns a computation.

The laws say that flattening three layers does not depend on which two layers you flatten first, and that wrapping then flattening (on the inside or the outside) does nothing. They are the laws of a monoid — written one dimension up, with composition of functors in place of multiplication. That analogy is precise: monads on C\mathcal{C} are the monoid objects in the monoidal category of endofunctors of C\mathcal{C} (see monoidal categories).

An algebra is a place where wrapped things can be evaluated: a:TA→Aa : TA \to A. The unit law says that evaluating a trivially wrapped element returns it; the associativity law says that evaluating the inner layers first and then the outer layer is the same as flattening first and then evaluating. For lists this is the generalised associative law of a monoid, and that is the whole story: the algebras of the list monad are exactly the monoids.

DefinitionsH

Monads, algebras and Kleisli arrows

Throughout, C\mathcal{C} is a category and composition is written g∘fg \circ f ("gg after ff"). Recall from natural transformations how to whisker: for α:S⇒S′\alpha : S \Rightarrow S' and a functor TT, (Tα)X=T(αX)(T\alpha)_X = T(\alpha_X) and (αT)X=αTX(\alpha T)_X = \alpha_{TX}.

Definition— monad

A monad on C\mathcal{C} is a triple (T,η,μ)(T, \eta, \mu) consisting of a functor T:C→CT : \mathcal{C} \to \mathcal{C} and natural transformations η:idC⇒T\eta : \mathrm{id}_{\mathcal{C}} \Rightarrow T (the unit) and μ:T2⇒T\mu : T^2 \Rightarrow T (the multiplication) such that for every object XX

μX∘TμX=μX∘μTXandμX∘ηTX=idTX=μX∘TηX.\mu_X \circ T\mu_X = \mu_X \circ \mu_{TX} \qquad\text{and}\qquad \mu_X \circ \eta_{TX} = \mathrm{id}_{TX} = \mu_X \circ T\eta_X .

The laws are the commutativity of the following diagrams (associativity on the left, the two unit laws on the right).

T3XT^3X
T2XT^2X
T2XT^2X
TXTX
TXTX
T2XT^2X
TXTX
TXTX
TμXT\mu_X
μTX\mu_{TX}
μX\mu_X
μX\mu_X
ηTX\eta_{TX}
TηXT\eta_X
μX\mu_X
id\mathrm{id}
id\mathrm{id}
The monad laws: associativity of μ\mu (left) and the unit laws (right).

Definition— algebra for a monad (Eilenberg–Moore algebra)

A TT-algebra is a pair (A,a)(A, a) of an object AA and a morphism a:TA→Aa : TA \to A (the structure map) such that

a∘ηA=idAanda∘Ta=a∘μA.a \circ \eta_A = \mathrm{id}_A \qquad\text{and}\qquad a \circ Ta = a \circ \mu_A .

A morphism of algebras f:(A,a)→(B,b)f : (A, a) \to (B, b) is a morphism f:A→Bf : A \to B with f∘a=b∘Tff \circ a = b \circ Tf. Algebras and their morphisms form the Eilenberg–Moore category CT\mathcal{C}^T, with a forgetful functor UT:CT→CU^T : \mathcal{C}^T \to \mathcal{C}. For every XX, the pair (TX,μX)(TX, \mu_X) is an algebra — the free algebra on XX — and FTX=(TX,μX)F^T X = (TX, \mu_X), FTf=TfF^T f = Tf defines a functor FT:C→CTF^T : \mathcal{C} \to \mathcal{C}^T.

AA
TATA
AA
T2AT^2A
TATA
TATA
AA
ηA\eta_A
aa
id\mathrm{id}
TaTa
μA\mu_A
aa
aa
The algebra laws: the unit law (left) and the associativity law (right).

Definition— Kleisli category

The Kleisli category CT\mathcal{C}_T has the same objects as C\mathcal{C}, and a morphism A⇝BA \rightsquigarrow B in CT\mathcal{C}_T is a morphism f:A→TBf : A \to TB in C\mathcal{C} (a Kleisli arrow). The Kleisli composite of f:A→TBf : A \to TB and g:B→TCg : B \to TC and the Kleisli identity are

g∘Tf=μC∘Tg∘f:A→TC,idAT=ηA:A→TA.g \circ_T f = \mu_C \circ Tg \circ f : A \to TC, \qquad \mathrm{id}^T_A = \eta_A : A \to TA .

There are functors FT:C→CTF_T : \mathcal{C} \to \mathcal{C}_T, FTA=AF_T A = A, FT(h)=ηB∘hF_T(h) = \eta_B \circ h for h:A→Bh : A \to B, and UT:CT→CU_T : \mathcal{C}_T \to \mathcal{C}, UTA=TAU_T A = TA, UT(f)=μB∘TfU_T(f) = \mu_B \circ Tf for f:A→TBf : A \to TB.

Think of a Kleisli arrow as a "generalised function" from AA to BB: many-valued (list or power-set monad), partial (maybe monad), random (distribution monad), or effectful (in programming).

Definition— monadic functor

A functor G:D→CG : \mathcal{D} \to \mathcal{C} is monadic if it has a left adjoint FF and the comparison functor K:D→CGFK : \mathcal{D} \to \mathcal{C}^{GF} (constructed below) is an equivalence of categories. Informally: the objects of D\mathcal{D} are exactly "objects of C\mathcal{C} with TT-algebra structure".

Worked examplesH

Examples and non-examples

Example— The list (free monoid) monad on Set

TX=List(X)TX = \mathrm{List}(X), the set of finite sequences; TfTf applies ff to each entry; ηX(x)=[x]\eta_X(x) = [x]; μX\mu_X concatenates a list of lists. Associativity says that flattening a list of lists of lists inside-first or outside-first gives the same list; the unit laws say μ[w]=w\mu[w] = w and μ[[x1],…,[xn]]=[x1,…,xn]\mu[[x_1], \dots, [x_n]] = [x_1, \dots, x_n]. All three are proved by induction on the outer list (and in Lean below). This monad comes from the adjunction between the free-monoid functor and the forgetful functor Mon→Set\cat{Mon} \to \cat{Set}.

Example— The power-set monad on Set

TX=PXTX = \mathcal{P}X; Tf(S)=f[S]Tf(S) = f[S] (direct image); ηX(x)={x}\eta_X(x) = \{x\}; μX(S)=⋃S\mu_X(\mathcal{S}) = \bigcup \mathcal{S}. Associativity is ⋃S∈S⋃S=⋃⋃S\bigcup_{\mathcal{S} \in \mathfrak{S}} \bigcup \mathcal{S} = \bigcup \bigcup \mathfrak{S} for S∈PPPX\mathfrak{S} \in \mathcal{P}\mathcal{P}\mathcal{P}X; the unit laws are ⋃{S}=S\bigcup\{S\} = S and ⋃x∈S{x}=S\bigcup_{x \in S} \{x\} = S.

An algebra a:PA→Aa : \mathcal{P}A \to A is a complete join-semilattice: define x≤y  ⟺  a{x,y}=yx \le y \iff a\{x, y\} = y. Conversely, a poset with all joins gives a(S)=⋁Sa(S) = \bigvee S. (Sketch: the associativity law gives a(S)=a{a(S1),a(S2)}a(S) = a\{a(S_1), a(S_2)\} whenever S=S1∪S2S = S_1 \cup S_2, from which ≤\le is a partial order and a(S)a(S) is the least upper bound of SS; the unit law gives a{x}=xa\{x\} = x.) Algebra morphisms are maps preserving all joins. A Kleisli arrow A→PBA \to \mathcal{P}B is a relation from AA to BB, and Kleisli composition is composition of relations: SetP≅Rel\cat{Set}_{\mathcal{P}} \cong \cat{Rel}.

Example— The maybe (exception) monad on Set

TX=X⊔{⊥}TX = X \sqcup \{\bot\}; ηX(x)=x\eta_X(x) = x; μX\mu_X collapses the two copies of ⊥\bot in X⊔{⊥}⊔{⊥}X \sqcup \{\bot\} \sqcup \{\bot\}. An algebra a:A⊔{⊥}→Aa : A \sqcup \{\bot\} \to A must be the identity on AA (unit law), and the associativity law then holds automatically, so an algebra is just a base point a(⊥)∈Aa(\bot) \in A: SetT\cat{Set}^T is the category of pointed sets. (The empty set has no algebra structure.) A Kleisli arrow A→B⊔{⊥}A \to B \sqcup \{\bot\} is a partial function, and SetT\cat{Set}_T is the category of sets and partial functions.

Example— Closure operators: monads on a poset

Regard a poset (P,≤)(P, \le) as a category with a unique arrow x→yx \to y when x≤yx \le y. A functor c:P→Pc : P \to P is a monotone map; η\eta says x≤c(x)x \le c(x); μ\mu says c(c(x))≤c(x)c(c(x)) \le c(x); all diagrams commute automatically. So a monad on a poset is exactly a closure operator (and then c∘c=cc \circ c = c). Its algebras are the elements with c(x)≤xc(x) \le x, i.e. the closed elements. Topological closure on PX\mathcal{P}X, the subgroup generated by a subset, the convex hull and the radical of an ideal are all examples; so is S↦S⊥⊥S \mapsto S^{\perp\perp} for any Galois connection.

Example— The distribution monad

DXDX is the set of finitely supported probability distributions on XX; DfDf pushes distributions forward; ηX(x)=δx\eta_X(x) = \delta_x (point mass); μX(Φ)(x)=∑φΦ(φ) φ(x)\mu_X(\Phi)(x) = \sum_{\varphi} \Phi(\varphi)\, \varphi(x) averages a distribution of distributions. A Kleisli arrow X→DYX \to DY is a Markov kernel — for finite X,YX, Y, a stochastic matrix — and Kleisli composition is the Chapman–Kolmogorov formula: the product of stochastic matrices (see Markov chains). Expectation E:DR→R\mathbb{E} : D\R \to \R is an algebra; its associativity law is the tower property E[E[Z∣W]]=E[Z]\mathbb{E}[\mathbb{E}[Z \mid W]] = \mathbb{E}[Z] for finitely supported random variables. More generally every convex subset of a real vector space is a DD-algebra via barycentres — but so is every join-semilattice (send a distribution to the join of its support), so "DD-algebra" (also called a convex space) is broader than "convex set".

Example— Monads from adjunctions

Every adjunction gives a monad (proved below). The free group functor F⊣U:Grp→SetF \dashv U : \cat{Grp} \to \cat{Set} gives the monad UFUF sending XX to the set of reduced words in X±1X^{\pm 1}. For a ring RR, extension of scalars R⊗Z−⊣U:R-Mod→AbR \otimes_{\Z} - \dashv U : R\text{-}\cat{Mod} \to \cat{Ab} gives the monad R⊗Z−R \otimes_{\Z} - on Ab\cat{Ab}, whose algebras are RR-modules. The discrete-space functor Disc⊣U:Top→Set\mathrm{Disc} \dashv U : \cat{Top} \to \cat{Set} gives the identity monad, since U∘Disc=idU \circ \mathrm{Disc} = \mathrm{id}; this will show that Top\cat{Top} is not monadic over Set\cat{Set}.

Example— A non-example: the wrong multiplication

Keep P\mathcal{P} and ηX(x)={x}\eta_X(x) = \{x\} but flatten by intersection, μX(S)=⋂S\mu_X(\mathcal{S}) = \bigcap \mathcal{S}. The associativity law and the left unit law ⋂{S}=S\bigcap\{S\} = S hold (with the convention ⋂∅=X\bigcap \varnothing = X), but the right unit law fails: μ(Pη({0,1}))={0}∩{1}=∅≠{0,1}\mu(\mathcal{P}\eta(\{0, 1\})) = \{0\} \cap \{1\} = \varnothing \neq \{0, 1\}. Nor is this μ\mu natural: for a non-injective ff, f[S1∩S2]f[S_1 \cap S_2] can be smaller than f[S1]∩f[S2]f[S_1] \cap f[S_2]. (The experiment below finds the unit-law counterexample by search.)

ProofH

Adjunctions, Kleisli and Eilenberg–Moore

Let F:C→DF : \mathcal{C} \to \mathcal{D} be left adjoint to G:D→CG : \mathcal{D} \to \mathcal{C}, with unit η:idC⇒GF\eta : \mathrm{id}_{\mathcal{C}} \Rightarrow GF and counit ε:FG⇒idD\varepsilon : FG \Rightarrow \mathrm{id}_{\mathcal{D}} satisfying the triangle identities εFX∘FηX=idFX\varepsilon_{FX} \circ F\eta_X = \mathrm{id}_{FX} and GεB∘ηGB=idGBG\varepsilon_B \circ \eta_{GB} = \mathrm{id}_{GB}.

Theorem— Theorem 1 (every adjunction induces a monad; Huber)

(GF,η,GεF)(GF, \eta, G\varepsilon F) is a monad on C\mathcal{C}: its multiplication has components μX=G(εFX):GFGFX→GFX\mu_X = G(\varepsilon_{FX}) : GFGFX \to GFX.

Proof

μ\mu is natural because ε\varepsilon is. Associativity. Naturality of ε\varepsilon applied to the morphism εFX:FGFX→FX\varepsilon_{FX} : FGFX \to FX gives εFX∘FG(εFX)=εFX∘εFGFX\varepsilon_{FX} \circ FG(\varepsilon_{FX}) = \varepsilon_{FX} \circ \varepsilon_{FGFX}. Applying GG:

μX∘TμX=GεFX∘GFGεFX=G(εFX∘FGεFX)=G(εFX∘εFGFX)=μX∘μTX.\mu_X \circ T\mu_X = G\varepsilon_{FX} \circ GFG\varepsilon_{FX} = G(\varepsilon_{FX} \circ FG\varepsilon_{FX}) = G(\varepsilon_{FX} \circ \varepsilon_{FGFX}) = \mu_X \circ \mu_{TX}.

Left unit. μX∘ηTX=GεFX∘ηGFX=id\mu_X \circ \eta_{TX} = G\varepsilon_{FX} \circ \eta_{GFX} = \mathrm{id} by the second triangle identity at B=FXB = FX. Right unit. μX∘TηX=GεFX∘GFηX=G(εFX∘FηX)=G(idFX)=id\mu_X \circ T\eta_X = G\varepsilon_{FX} \circ GF\eta_X = G(\varepsilon_{FX} \circ F\eta_X) = G(\mathrm{id}_{FX}) = \mathrm{id} by the first triangle identity.

∎

Now go the other way: start with a monad (T,η,μ)(T, \eta, \mu) and look for adjunctions that induce it.

Theorem— Theorem 2 (the Kleisli adjunction; Kleisli 1965)

CT\mathcal{C}_T is a category, FTF_T and UTU_T are functors, FT⊣UTF_T \dashv U_T, and the monad induced by this adjunction is (T,η,μ)(T, \eta, \mu).

Proof

Identities. For f:A→TBf : A \to TB: ηB∘Tf=μB∘TηB∘f=f\eta_B \circ_T f = \mu_B \circ T\eta_B \circ f = f by the right unit law; and f∘TηA=μB∘Tf∘ηA=μB∘ηTB∘f=ff \circ_T \eta_A = \mu_B \circ Tf \circ \eta_A = \mu_B \circ \eta_{TB} \circ f = f by naturality of η\eta and the left unit law.

Associativity. For f:A→TBf : A \to TB, g:B→TCg : B \to TC, h:C→TDh : C \to TD:

(h∘Tg)∘Tf=μD∘TμD∘T2h∘Tg∘f=μD∘μTD∘T2h∘Tg∘f=μD∘Th∘μC∘Tg∘f=h∘T(g∘Tf),(h \circ_T g) \circ_T f = \mu_D \circ T\mu_D \circ T^2 h \circ Tg \circ f = \mu_D \circ \mu_{TD} \circ T^2 h \circ Tg \circ f = \mu_D \circ Th \circ \mu_C \circ Tg \circ f = h \circ_T (g \circ_T f),

using associativity of μ\mu and then naturality of μ\mu at hh (μTD∘T2h=Th∘μC\mu_{TD} \circ T^2 h = Th \circ \mu_C).

Functors. FT(k∘h)=η∘k∘h=(η∘k)∘T(η∘h)F_T(k \circ h) = \eta \circ k \circ h = (\eta \circ k) \circ_T (\eta \circ h) by naturality of η\eta and the unit law; UT(g∘Tf)=μ∘Tμ∘T2g∘Tf=μ∘μ∘T2g∘Tf=μ∘Tg∘μ∘Tf=UTg∘UTfU_T(g \circ_T f) = \mu \circ T\mu \circ T^2 g \circ Tf = \mu \circ \mu \circ T^2 g \circ Tf = \mu \circ Tg \circ \mu \circ Tf = U_T g \circ U_T f by the same two laws; identities are preserved by the unit laws.

Adjunction. CT(FTA,B)=C(A,TB)=C(A,UTB)\mathcal{C}_T(F_T A, B) = \mathcal{C}(A, TB) = \mathcal{C}(A, U_T B), and this identity bijection is natural in AA and BB (a direct check with the formulas above). Its unit is ηA\eta_A (the arrow corresponding to idAT\mathrm{id}^T_A) and its counit at BB is the Kleisli arrow idTB:TB⇝B\mathrm{id}_{TB} : TB \rightsquigarrow B.

The induced monad. UTFTA=TAU_T F_T A = TA and UTFTh=μB∘TηB∘Th=ThU_T F_T h = \mu_B \circ T\eta_B \circ Th = Th, so UTFT=TU_T F_T = T; the unit is η\eta; and UT(εFTA)=UT(idTA)=μA∘T(idTA)=μAU_T(\varepsilon_{F_T A}) = U_T(\mathrm{id}_{TA}) = \mu_A \circ T(\mathrm{id}_{TA}) = \mu_A.

∎

Theorem— Theorem 3 (the Eilenberg–Moore adjunction; Eilenberg and Moore 1965)

FT⊣UT:CT→CF^T \dashv U^T : \mathcal{C}^T \to \mathcal{C}, and the monad induced by this adjunction is (T,η,μ)(T, \eta, \mu).

Proof

First, (TX,μX)(TX, \mu_X) is an algebra: the unit and associativity laws for it are the left unit law and the associativity law of the monad; and TfTf is an algebra map (TX,μX)→(TY,μY)(TX, \mu_X) \to (TY, \mu_Y) by naturality of μ\mu. For an algebra (A,a)(A, a) define

Φ:CT((TX,μX),(A,a))→C(X,A),Φ(f)=f∘ηX;Ψ(g)=a∘Tg.\Phi : \mathcal{C}^T\big((TX, \mu_X), (A, a)\big) \to \mathcal{C}(X, A),\quad \Phi(f) = f \circ \eta_X; \qquad \Psi(g) = a \circ Tg .

Ψ(g)\Psi(g) is an algebra map: a∘Tg∘μX=a∘μA∘T2g=a∘Ta∘T2g=a∘T(a∘Tg)a \circ Tg \circ \mu_X = a \circ \mu_A \circ T^2 g = a \circ Ta \circ T^2 g = a \circ T(a \circ Tg) (naturality of μ\mu, then the associativity law of aa). The maps are inverse: ΦΨ(g)=a∘Tg∘ηX=a∘ηA∘g=g\Phi\Psi(g) = a \circ Tg \circ \eta_X = a \circ \eta_A \circ g = g (naturality of η\eta, unit law of aa), and for an algebra map ff, ΨΦ(f)=a∘Tf∘TηX=f∘μX∘TηX=f\Psi\Phi(f) = a \circ Tf \circ T\eta_X = f \circ \mu_X \circ T\eta_X = f (algebra map, right unit law). Naturality in XX and (A,a)(A, a) is immediate. The unit of the adjunction is Φ(id)=ηX\Phi(\mathrm{id}) = \eta_X, and the counit at (A,a)(A, a) is Ψ(idA)=a\Psi(\mathrm{id}_A) = a, an algebra map (TA,μA)→(A,a)(TA, \mu_A) \to (A, a). Finally UTFT=TU^T F^T = T and UTεFTX=μXU^T \varepsilon_{F^T X} = \mu_X.

∎

So every monad arises from an adjunction, generally from many. The two constructions are the extreme ones.

Theorem— Theorem 4 (comparison functors)

Let F⊣GF \dashv G induce T=GFT = GF. Then K:D→CTK : \mathcal{D} \to \mathcal{C}^T, K(B)=(GB,GεB)K(B) = (GB, G\varepsilon_B), K(h)=GhK(h) = Gh, is a functor with UTK=GU^T K = G and KF=FTK F = F^T. Likewise L:CT→DL : \mathcal{C}_T \to \mathcal{D}, L(A)=FAL(A) = FA, L(f)=εFB∘FfL(f) = \varepsilon_{FB} \circ Ff for f:A→GFBf : A \to GFB, is a functor with LFT=FL F_T = F and GL=UTG L = U_T. Each is the unique functor with these properties; hence the Kleisli adjunction is initial and the Eilenberg–Moore adjunction terminal among adjunctions inducing TT.

Proof

We check that KK is well defined. Unit law: GεB∘ηGB=idG\varepsilon_B \circ \eta_{GB} = \mathrm{id} (triangle identity). Associativity law: GεB∘T(GεB)=G(εB∘FGεB)=G(εB∘εFGB)=GεB∘μGBG\varepsilon_B \circ T(G\varepsilon_B) = G(\varepsilon_B \circ FG\varepsilon_B) = G(\varepsilon_B \circ \varepsilon_{FGB}) = G\varepsilon_B \circ \mu_{GB} (naturality of ε\varepsilon at εB\varepsilon_B). For h:B→B′h : B \to B', Gh∘GεB=G(εB′∘FGh)=GεB′∘T(Gh)Gh \circ G\varepsilon_B = G(\varepsilon_{B'} \circ FGh) = G\varepsilon_{B'} \circ T(Gh), so GhGh is an algebra map. Clearly UTK=GU^T K = G, and KFX=(GFX,GεFX)=(TX,μX)=FTXKFX = (GFX, G\varepsilon_{FX}) = (TX, \mu_X) = F^T X, with KFf=Tf=FTfKFf = Tf = F^T f. The checks for LL are similar (functoriality uses the triangle identity εFA∘FηA=id\varepsilon_{FA} \circ F\eta_A = \mathrm{id} and naturality of ε\varepsilon). For uniqueness, see Mac Lane, Categories for the Working Mathematician, VI.3 Theorem 1 and VI.5 Theorem 3.

∎

Applied to the Eilenberg–Moore adjunction, the functor L:CT→CTL : \mathcal{C}_T \to \mathcal{C}^T sends AA to the free algebra FTAF^T A and f:A→TBf : A \to TB to μB∘Tf\mu_B \circ Tf. It is fully faithful: on morphisms it is the bijection Ψ:C(A,TB)≅CT(FTA,FTB)\Psi : \mathcal{C}(A, TB) \cong \mathcal{C}^T(F^T A, F^T B) of Theorem 3. So the Kleisli category is (equivalent to) the full subcategory of free algebras. Whether it is all of CT\mathcal{C}^T depends on the monad.

Theorem— Proposition 5 (Kleisli and Eilenberg–Moore can differ)

For the maybe monad, CT→CT\mathcal{C}_T \to \mathcal{C}^T is an equivalence. For the list monad, CT\mathcal{C}_T and CT≃Mon\mathcal{C}^T \simeq \cat{Mon} are not equivalent by any functor.

Proof

Maybe. Every pointed set (X,x0)(X, x_0) is isomorphic to the free algebra on X∖{x0}X \setminus \{x_0\}, so the fully faithful functor CT→CT\mathcal{C}_T \to \mathcal{C}^T is essentially surjective, hence an equivalence: sets and partial functions are equivalent to pointed sets.

List. An equivalence of categories preserves endomorphism monoids up to isomorphism (it is fully faithful). In Mon\cat{Mon}, the monoid Z/2\Z/2 has exactly two endomorphisms (1↦01 \mapsto 0 and 1↦11 \mapsto 1). In CT\mathcal{C}_T, the endomorphisms of AA are the functions A→List(A)A \to \mathrm{List}(A): one if A=∅A = \varnothing, infinitely many otherwise. So no object of CT\mathcal{C}_T can correspond to Z/2\Z/2.

∎

ExplanationH

Beck's monadicity theorem

Which adjunctions are "the Eilenberg–Moore one" up to equivalence? A parallel pair f,g:A⇉Bf, g : A \rightrightarrows B in D\mathcal{D} is GG-split if Gf,GgGf, Gg has a split coequaliser in C\mathcal{C}: a morphism e:GB→Ze : GB \to Z with e∘Gf=e∘Gge \circ Gf = e \circ Gg, together with s:Z→GBs : Z \to GB and t:GB→GAt : GB \to GA such that e∘s=idZe \circ s = \mathrm{id}_Z, Gf∘t=idGBGf \circ t = \mathrm{id}_{GB} and Gg∘t=s∘eGg \circ t = s \circ e. (Split coequalisers are coequalisers, and are preserved by every functor.)

Theorem— Beck's monadicity theorem (Beck 1967)

A functor G:D→CG : \mathcal{D} \to \mathcal{C} is monadic if and only if

  1. GG has a left adjoint,
  2. GG reflects isomorphisms, and
  3. D\mathcal{D} has coequalisers of GG-split pairs, and GG preserves them.

The proof constructs a left adjoint to the comparison functor KK by sending an algebra (A,a)(A, a) to the coequaliser in D\mathcal{D} of the GG-split pair Fa,εFA:FGFA⇉FAF a, \varepsilon_{FA} : FGFA \rightrightarrows FA (every algebra is canonically a coequaliser of free algebras), and then shows that unit and counit are isomorphisms. Full proofs: Mac Lane, CWM VI.7; Riehl, Category Theory in Context, Theorem 5.5.1. Mathlib proves it (cited in the formal section).

Example— Groups are monadic over Set

U:Grp→SetU : \cat{Grp} \to \cat{Set} has the free-group left adjoint, and a bijective homomorphism is an isomorphism, so UU reflects isomorphisms. Sketch of condition 3. Let f,g:H⇉Kf, g : H \rightrightarrows K be homomorphisms with a split coequaliser e:K→Ze : K \to Z of sets, with s,ts, t as above. If e(x)=e(y)e(x) = e(y), then with h=t(x)h = t(x) and h′=t(y)h' = t(y) we get x=f(h)x = f(h), g(h)=s(e(x))=s(e(y))=g(h′)g(h) = s(e(x)) = s(e(y)) = g(h') and y=f(h′)y = f(h'). So the relation e(x)=e(y)e(x) = e(y) is the composite of the relation R={(f(h),g(h))}R = \{(f(h), g(h))\} with its converse. RR is the image of the homomorphism (f,g):H→K×K(f, g) : H \to K \times K, hence a subgroup of K×KK \times K, and composites and converses of subgroups of K×KK \times K are again subgroups. So ker⁡e\ker e is a congruence on KK, ZZ carries a unique group structure making ee a homomorphism, and one checks that ee is then a coequaliser of f,gf, g in Grp\cat{Grp}, preserved by UU. By Beck, Grp≃SetUF\cat{Grp} \simeq \cat{Set}^{UF}.

The same argument (or Linton's theorem that every variety of universal algebras is monadic) applies to Ab\cat{Ab}, Ring\cat{Ring}, R-ModR\text{-}\cat{Mod} and Mon\cat{Mon}. The category of compact Hausdorff spaces is monadic over Set\cat{Set} too, via the ultrafilter monad (Manes 1969) — although it is not a variety of finitary algebras.

Example— Topological spaces are not monadic over Set

The left adjoint of U:Top→SetU : \cat{Top} \to \cat{Set} is the discrete-space functor, so the induced monad is the identity monad, whose algebras are just sets (the unit law forces a=ida = \mathrm{id}). The comparison functor Top→Set\cat{Top} \to \cat{Set} is UU itself, and it is not an equivalence: the identity map from a two-point discrete space to a two-point indiscrete space is continuous and bijective but not a homeomorphism, so UU does not reflect isomorphisms (condition 2 fails). The same argument shows that posets are not monadic over Set\cat{Set}.

Example— Monads in programming (Moggi)

Model a programming language whose programs may have effects by a monad TT on a category of types: a program from AA to BB is a Kleisli arrow A→TBA \to TB, and running programs in sequence is Kleisli composition. Exceptions: TB=B+ETB = B + E. Nondeterminism: TB=PfinBTB = \mathcal{P}_{\mathrm{fin}}B or List(B)\mathrm{List}(B). Global state: TB=(B×S)STB = (B \times S)^S. Output to a log: TB=M×BTB = M \times B for a monoid MM. Probabilistic choice: TB=DBTB = DB. Moggi (1989, 1991) made this precise; Wadler brought it into functional programming, and in Haskell return is η\eta and >>= (bind) is Kleisli extension: f:A→TBf : A \to TB extends to f∗=μB∘Tf:TA→TBf^* = \mu_B \circ Tf : TA \to TB. A monad can equivalently be given as a Kleisli triple (T,η,(−)∗)(T, \eta, (-)^*) satisfying η∗=id\eta^* = \mathrm{id}, f∗∘η=ff^* \circ \eta = f and g∗∘f∗=(g∗∘f)∗g^* \circ f^* = (g^* \circ f)^* — which are exactly the three Kleisli category laws, i.e. Haskell's "monad laws". The monads came from algebra and topology; programming found them afterwards.

Formal mathematicsF

Monads in Lean

The Lean module works at two levels. First, with plain functions on types, it checks the monad and Kleisli laws for lists by induction, and proves in full that list-algebras are monoids:

list_monad_lawsLean 4Proved here from basic factsFormally verified
/-- **The list monad satisfies the monad laws.** Here `T X = List X`, the unit `η` sends `x` to
the one-element list `[x]`, and the multiplication `μ` flattens a list of lists.
1. associativity `μ ∘ Tμ = μ ∘ μT`: flattening the inner lists first, or the outer list first,
   gives the same list;
2. left unit `μ ∘ ηT = id`: flattening `[xs]` gives `xs`;
3. right unit `μ ∘ Tη = id`: flattening `[[x₁], …, [xₙ]]` gives `[x₁, …, xₙ]`.
Each law is proved by induction on the outer list. -/
theorem list_monad_laws {α : Type u} :
    (∀ xsss : List (List (List α)), (xsss.map List.flatten).flatten = xsss.flatten.flatten) ∧
    (∀ xs : List α, [xs].flatten = xs) ∧
    (∀ xs : List α, (xs.map fun x => [x]).flatten = xs) := by
  refine ⟨fun xsss => ?_, fun xs => by simp, fun xs => ?_⟩
  · induction xsss with
    | nil => rfl
    | cons xss rest ih =>
      simp only [List.map_cons, List.flatten_cons, List.flatten_append, ih]
  · induction xs with
    | nil => rfl
    | cons x rest ih => simp only [List.map_cons, List.flatten_cons, ih, List.singleton_append]
Axioms used: propextformal/Lumenary/Monads.leanTry it in the Lean web editor
listKleisliLean 4Formally verified
/-- **Kleisli composition for the list monad.** A Kleisli arrow `α → List β` is a
"many-valued function". To compose `f : α → List β` with `g : β → List γ`, apply `g` to every
output of `f` and flatten: in categorical notation `μ ∘ T g ∘ f`. -/
def listKleisli {α : Type u} {β : Type v} {γ : Type w} (f : α → List β) (g : β → List γ) :
    α → List γ :=
  fun a => (f a).flatMap g
Axioms used: No axiomsformal/Lumenary/Monads.leanTry it in the Lean web editor
list_kleisli_lawsLean 4Proved here from basic factsFormally verified
/-- **The Kleisli category of the list monad is a category.** Kleisli composition is associative,
and `η = fun a => [a]` is a two-sided identity. Associativity is core Lean's `List.flatMap_assoc`;
the identity laws are short computations. -/
theorem list_kleisli_laws {α β γ δ : Type u} (f : α → List β) (g : β → List γ)
    (h : γ → List δ) :
    listKleisli (listKleisli f g) h = listKleisli f (listKleisli g h) ∧
    listKleisli (fun a => [a]) f = f ∧
    listKleisli f (fun b => [b]) = f := by
  refine ⟨?_, ?_, ?_⟩
  · funext a
    exact List.flatMap_assoc
  · funext a
    simp [listKleisli]
  · funext a
    simp [listKleisli]
Axioms used: propext, Quot.soundformal/Lumenary/Monads.leanTry it in the Lean web editor

A list algebra is an evaluation map with the two laws. The key lemma is the human proof's first step: an algebra is determined by evaluating two-element lists.

ListAlgebraLean 4Formally verified
/-- An **algebra for the list monad** on a type `X`: an evaluation map `act : List X → X` such
that evaluating a one-element list returns its element (`act ∘ η = id`), and evaluating a list of
lists "inside first" or "flatten first" agrees (`act ∘ T act = act ∘ μ`). -/
structure ListAlgebra (X : Type u) where
  /-- Evaluate a list of elements to a single element. -/
  act : List X → X
  /-- The unit law `act [x] = x`. -/
  unit : ∀ x : X, act [x] = x
  /-- The associativity law: evaluate the inner lists first, or flatten first. -/
  assoc : ∀ xss : List (List X), act (xss.map act) = act xss.flatten
Axioms used: No axiomsformal/Lumenary/Monads.leanTry it in the Lean web editor
act_consLean 4Proved here from basic factsFormally verified
/-- In a list algebra, evaluating `x :: xs` is the same as evaluating the two-element list
`[x, act xs]`:
`act [x, act xs] = act [act [x], act xs] = act (flatten [[x], xs]) = act (x :: xs)`,
using the unit law and then the associativity law. -/
theorem act_cons (A : ListAlgebra X) (x : X) (xs : List X) :
    A.act (x :: xs) = A.act [x, A.act xs] := by
  calc A.act (x :: xs) = A.act ([[x], xs].flatten) := by simp
    _ = A.act ([[x], xs].map A.act) := (A.assoc [[x], xs]).symm
    _ = A.act [x, A.act xs] := by simp [A.unit]
Axioms used: propextformal/Lumenary/Monads.leanTry it in the Lean web editor
toMonoidLean 4Formally verified
/-- **Every list algebra is a monoid.** Multiply by evaluating two-element lists,
`x * y = act [x, y]`, and take `1 = act []`. The monoid laws follow from the algebra laws:
for example `(x * y) * z = act [act [x, y], act [z]] = act [x, y, z]`, and likewise
`x * (y * z) = act [x, y, z]`. -/
@[instance_reducible]
def toMonoid (A : ListAlgebra X) : Monoid X where
  mul x y := A.act [x, y]
  one := A.act []
  mul_assoc x y z := by
    show A.act [A.act [x, y], z] = A.act [x, A.act [y, z]]
    have h₁ : A.act [A.act [x, y], z] = A.act [x, y, z] := by
      calc A.act [A.act [x, y], z] = A.act ([[x, y], [z]].map A.act) := by simp [A.unit]
        _ = A.act [x, y, z] := by rw [A.assoc]; simp
    have h₂ : A.act [x, A.act [y, z]] = A.act [x, y, z] := by
      calc A.act [x, A.act [y, z]] = A.act ([[x], [y, z]].map A.act) := by simp [A.unit]
        _ = A.act [x, y, z] := by rw [A.assoc]; simp
    rw [h₁, h₂]
  one_mul x := by
    show A.act [A.act [], x] = x
    calc A.act [A.act [], x] = A.act ([[], [x]].map A.act) := by simp [A.unit]
      _ = x := by rw [A.assoc]; simp [A.unit]
  mul_one x := by
    show A.act [x, A.act []] = x
    calc A.act [x, A.act []] = A.act ([[x], []].map A.act) := by simp [A.unit]
      _ = x := by rw [A.assoc]; simp [A.unit]
Axioms used: propextformal/Lumenary/Monads.leanTry it in the Lean web editor
ofMonoidLean 4Formally verified
/-- **Every monoid is a list algebra**: evaluate a list by multiplying it out, `act = List.prod`.
The unit law is `List.prod_singleton` and the associativity law is core Lean's
`List.prod_flatten` (multiplying blockwise, then multiplying the results, is multiplying
everything). -/
def ofMonoid (M : Type u) [Monoid M] : ListAlgebra M where
  act := List.prod
  unit _ := List.prod_singleton
  assoc _ := List.prod_flatten.symm
Axioms used: propextformal/Lumenary/Monads.leanTry it in the Lean web editor
act_eq_prodLean 4Proved here from basic factsFormally verified
/-- **A list algebra is determined by its binary multiplication and unit.** Evaluating any list
is multiplying it out in the monoid `A.toMonoid`. Proof by induction on the list, using
`act_cons` at each step. -/
theorem act_eq_prod (A : ListAlgebra X) (xs : List X) :
    A.act xs = @List.prod X A.toMonoid.toMul A.toMonoid.toOne xs := by
  induction xs with
  | nil => rfl
  | cons x xs ih =>
    rw [act_cons, ih]
    rfl
Axioms used: propextformal/Lumenary/Monads.leanTry it in the Lean web editor

The theorem "algebras for the list monad are exactly monoids" is then an explicit bijection between the two kinds of structure on a type:

listAlgebraEquivMonoidLean 4Proved here from basic factsFormally verified
/-- **Algebras for the list monad are exactly monoids.** On any type `X`, list-algebra structures
correspond bijectively to monoid structures: send an algebra to its binary multiplication, and a
monoid to `List.prod`. Going around one way uses `act_eq_prod`; going around the other way only
has to check that the multiplications agree (`Monoid.ext`), and `List.prod [x, y] = x * (y * 1)`. -/
def listAlgebraEquivMonoid (X : Type u) : ListAlgebra X ≃ Monoid X where
  toFun A := A.toMonoid
  invFun m := @ListAlgebra.ofMonoid X m
  left_inv A := by
    ext xs
    exact (A.act_eq_prod xs).symm
  right_inv m := by
    let _ := m
    apply Monoid.ext
    funext x y
    show List.prod [x, y] = x * y
    simp
Axioms used: propext, Quot.soundformal/Lumenary/Monads.leanTry it in the Lean web editor
optionAlgebraEquivLean 4Proved here from basic factsFormally verified
/-- **Algebras for the maybe monad are exactly pointed sets.** An `Option`-algebra on `X` is
determined by where it sends `none`, and every choice of base point gives an algebra (with
`act = fun o => o.getD a`; the associativity law then holds automatically, by checking the three
shapes `none`, `some none`, `some (some x)`). -/
def optionAlgebraEquiv (X : Type u) : OptionAlgebra X ≃ X where
  toFun A := A.act none
  invFun a :=
    { act := fun o => o.getD a
      unit := fun _ => rfl
      assoc := by
        intro oo
        rcases oo with _ | _ | x <;> rfl }
  left_inv A := by
    rcases A with ⟨act, unit, assoc⟩
    have h : (fun o => o.getD (act none)) = act := by
      funext o
      cases o with
      | none => rfl
      | some x => exact (unit x).symm
    simp only [OptionAlgebra.mk.injEq]
    exact h
  right_inv _ := rfl
Axioms used: propext, Quot.soundformal/Lumenary/Monads.leanTry it in the Lean web editor

Second, Mathlib has the general theory: CategoryTheory.Monad, the Eilenberg–Moore category Monad.Algebra, Kleisli, Adjunction.toMonad, the comparison functor and Beck's theorem. The following are one-line applications of Mathlib, recording Theorems 1–4 and Beck's theorem in Mathlib's language (note that Mathlib writes composition in diagrammatic order: F ⋙ G is G∘FG \circ F):

adjunction_monadLean 4Applies a library theoremFormally verified
/-- **Every adjunction induces a monad.** For `F ⊣ G` with unit `η` and counit `ε`, the monad
`h.toMonad` (Mathlib's `Adjunction.toMonad`) has underlying functor `G ∘ F` (written `F ⋙ G` in
diagrammatic order), unit `η`, and multiplication `μ_X = G(ε_{F X})`. -/
theorem adjunction_monad {F : C ⥤ D} {G : D ⥤ C} (h : F ⊣ G) (X : C) :
    (h.toMonad : C ⥤ C) = F ⋙ G ∧ h.toMonad.η = h.unit ∧
      h.toMonad.μ.app X = G.map (h.counit.app (F.obj X)) :=
  ⟨rfl, rfl, rfl⟩
Axioms used: propext, Classical.choice, Quot.soundformal/Lumenary/Monads.leanTry it in the Lean web editor
kleisli_inducesLean 4Applies a library theoremFormally verified
/-- **The Kleisli adjunction induces the monad.** For a monad `T`, the free functor
`C ⥤ Kleisli T` followed by the forgetful functor `Kleisli T ⥤ C` is isomorphic to `T`
(Mathlib's `Kleisli.Adjunction.toKleisliCompFromKleisliIsoSelf`). -/
theorem kleisli_induces (T : Monad C) :
    Nonempty (Kleisli.Adjunction.toKleisli T ⋙ Kleisli.Adjunction.fromKleisli T ≅
      (T : C ⥤ C)) :=
  ⟨Kleisli.Adjunction.toKleisliCompFromKleisliIsoSelf T⟩
Axioms used: propext, Classical.choice, Quot.soundformal/Lumenary/Monads.leanTry it in the Lean web editor
eilenberg_moore_inducesLean 4Applies a library theoremFormally verified
/-- **The Eilenberg–Moore adjunction induces the monad.** The free-algebra functor
`T.free : C ⥤ T.Algebra` is left adjoint to the forgetful functor (`T.adj`), and the monad of
this adjunction is isomorphic to `T` (Mathlib's `Adjunction.adjToMonadIso`). -/
theorem eilenberg_moore_induces (T : Monad C) : Nonempty (T.adj.toMonad ≅ T) :=
  ⟨Adjunction.adjToMonadIso T⟩
Axioms used: propext, Classical.choice, Quot.soundformal/Lumenary/Monads.leanTry it in the Lean web editor
comparisonLean 4Applies a library theoremFormally verified
/-- **The comparison functor.** For any adjunction `F ⊣ G` with monad `T = G F`, the functor
`K = Monad.comparison h : D ⥤ T.Algebra` sends `B` to the algebra `(G B, G ε_B)`. It is
compatible with both adjunctions: `K ∘ F` is the free-algebra functor (`Monad.left_comparison`)
and the forgetful functor after `K` is `G` (`Monad.comparisonForget`). -/
theorem comparison {F : C ⥤ D} {G : D ⥤ C} (h : F ⊣ G) :
    F ⋙ Monad.comparison h = h.toMonad.free ∧
      Nonempty (Monad.comparison h ⋙ h.toMonad.forget ≅ G) :=
  ⟨Monad.left_comparison h, ⟨Monad.comparisonForget h⟩⟩
Axioms used: propext, Classical.choice, Quot.soundformal/Lumenary/Monads.leanTry it in the Lean web editor
beckLean 4Applies a library theoremFormally verified
/-- **Beck's monadicity theorem** (one of Mathlib's versions,
`Monad.monadicOfHasPreservesReflectsGSplitCoequalizers`): if `G` has a left adjoint, `D` has
coequalisers of `G`-split pairs, and `G` preserves and reflects them, then `G` is monadic — the
comparison functor `D ⥤ T.Algebra` is an equivalence. -/
theorem beck {F : C ⥤ D} {G : D ⥤ C} (h : F ⊣ G) [Monad.HasCoequalizerOfIsSplitPair G]
    [Monad.PreservesColimitOfIsSplitPair G] [Monad.ReflectsColimitOfIsSplitPair G] :
    Nonempty (MonadicRightAdjoint G) :=
  ⟨Monad.monadicOfHasPreservesReflectsGSplitCoequalizers h⟩
Axioms used: propext, Classical.choice, Quot.soundformal/Lumenary/Monads.leanTry it in the Lean web editor
monads_are_monoidsLean 4Applies a library theoremFormally verified
/-- **A monad is a monoid in the category of endofunctors.** The category of monads on `C` is
equivalent to the category of monoid objects in `(C ⥤ C, ∘, 𝟭)` (Mathlib's
`Monad.monadMonEquiv`). -/
theorem monads_are_monoids (C : Type u) [Category.{v} C] :
    Nonempty (Monad C ≌ Mon (C ⥤ C)) :=
  ⟨Monad.monadMonEquiv C⟩
Axioms used: propext, Classical.choice, Quot.soundformal/Lumenary/Monads.leanTry it in the Lean web editor

What is and is not formalised. Independently proved here: the list monad and Kleisli laws, the equivalence between list-algebras and monoids, and the classification of maybe-algebras. Taken from Mathlib: the adjunction–monad correspondence, both canonical adjunctions, the comparison functor, Beck's theorem and monads as monoids. Not formalised: monadicity of Grp\cat{Grp}, the non-monadicity of Top\cat{Top}, and Proposition 5. The list-algebra statements are about functions List X → X; Mathlib's ofTypeMonad List packages the same monad as a CategoryTheory.Monad (Type u), and connecting the two is a routine but fiddly exercise in unfolding Mathlib's morphisms of types.

ComputationC

Searching for algebras; composing kernels

The first experiment searches every candidate structure map on small sets. It finds that maybe-algebras are base points, that power-set algebras on n≤3n \le 3 points are the n!n! chains with a(S)=sup⁡Sa(S) = \sup S, and that among the 243 unital binary operations on a 3-element set, the list-algebra laws hold exactly for the 33 associative ones — the monoids. It also catches the "intersection monad" breaking a unit law.

Counting algebras for the maybe, power-set and list monadsPythonExhaustive finite checkCounterexampleComputationally tested
"""Counting Eilenberg-Moore algebras on small finite sets.

An algebra for a monad T on a set X is a map a : T X -> X satisfying the unit
law a(eta x) = x and the associativity law a(T a) = a(mu). For three monads on
Set we search *every* candidate map on small sets and count the algebras:

* maybe monad  (T X = X + {None}): algebras should be base points;
* power-set monad (T X = subsets of X, mu = union): algebras should be
  complete join-semilattices, a(S) = sup S;
* list monad, restricted to unital binary operations on a 3-element set: the
  algebra laws (checked on a finite slice of nested lists) should hold exactly
  for the associative ones, i.e. for the monoids.

Finally a "monad" with the wrong multiplication (intersection instead of
union) is caught breaking a unit law. All searches are exhaustive over the
stated finite ranges; they illustrate, but do not prove, the theorems.
"""

import itertools

def maybe_algebras(n):
    """All maybe-algebras on {0..n-1}, by searching every map Option X -> X.

    A map is a tuple act of length n + 1; index n stands for None. Returns the
    maps satisfying the unit law and the associativity law.
    """
    def ev(act, o):
        return act[n if o is None else o]

    # oo ranges over the shapes None, Some None and Some (Some x).
    shapes = [None, ("some", None)] + [("some", x) for x in range(n)]
    found = []
    for act in itertools.product(range(n), repeat=n + 1):
        if any(act[x] != x for x in range(n)):
            continue
        ok = True
        for oo in shapes:
            inner = None if oo is None else oo[1]
            mapped = None if oo is None else ev(act, inner)
            ok = ok and ev(act, mapped) == ev(act, inner)
        if ok:
            found.append(act)
    return found

def subsets(n):
    """Subsets of {0..n-1} as bitmasks."""
    return list(range(1 << n))

def members(mask):
    """Elements of the subset encoded by a bitmask."""
    return [i for i in range(mask.bit_length()) if mask >> i & 1]

def is_powerset_algebra(act, n):
    """Check unit and associativity laws for a : P(X) -> X (dict on masks)."""
    if any(act[1 << x] != x for x in range(n)):
        return False
    subs = subsets(n)
    for family in range(1 << len(subs)):
        chosen = [subs[i] for i in members(family)]
        union = 0
        image = 0
        for s in chosen:
            union |= s
            image |= 1 << act[s]
        if act[image] != act[union]:
            return False
    return True

def powerset_algebras(n):
    """All power-set algebras on {0..n-1}, found by exhaustive search."""
    free = [s for s in subsets(n) if bin(s).count("1") != 1]
    found = []
    for values in itertools.product(range(n), repeat=len(free)):
        act = {1 << x: x for x in range(n)}
        act.update(zip(free, values))
        if is_powerset_algebra(act, n):
            found.append(act)
    return found

def order_of(act, n):
    """The relation x <= y iff a({x, y}) = y, as a set of pairs."""
    return {(x, y) for x in range(n) for y in range(n)
            if act[(1 << x) | (1 << y)] == y}

def is_least_upper_bound_map(act, rel, n):
    """True if a(S) is the least upper bound of S in rel, for every S."""
    for mask in subsets(n):
        s = members(mask)
        uppers = [y for y in range(n) if all((x, y) in rel for x in s)]
        if act[mask] not in uppers:
            return False
        if any((act[mask], v) not in rel for v in uppers):
            return False
    return True

def is_chain(rel, n):
    """True if rel is a total order on {0..n-1}."""
    total = all((x, y) in rel or (y, x) in rel for x in range(n)
                for y in range(n))
    anti = all(x == y or not ((x, y) in rel and (y, x) in rel)
               for x in range(n) for y in range(n))
    return total and anti

def unital_magmas(n):
    """All binary operations on {0..n-1} (as tuples of rows) with a unit."""
    out = []
    for table in itertools.product(range(n), repeat=n * n):
        rows = tuple(table[i * n:(i + 1) * n] for i in range(n))
        units = [e for e in range(n)
                 if all(rows[e][x] == x == rows[x][e] for x in range(n))]
        if units:
            out.append((rows, units[0]))
    return out

def fold(rows, unit, xs):
    """Evaluate a list by right-folding: x1 * (x2 * (... * (xn * e)))."""
    value = unit
    for x in reversed(xs):
        value = rows[x][value]
    return value

def list_algebra_law_holds(rows, unit, n, max_len=2):
    """Check fold(map fold xss) = fold(flatten xss) on a finite slice."""
    inner = [list(t) for k in range(max_len + 1)
             for t in itertools.product(range(n), repeat=k)]
    for k in range(max_len + 1):
        for xss in itertools.product(inner, repeat=k):
            lhs = fold(rows, unit, [fold(rows, unit, xs) for xs in xss])
            rhs = fold(rows, unit, [x for xs in xss for x in xs])
            if lhs != rhs:
                return False
    return True

def is_associative(rows, n):
    """True if the operation given by rows is associative."""
    return all(rows[rows[a][b]][c] == rows[a][rows[b][c]]
               for a in range(n) for b in range(n) for c in range(n))

def intersection_unit_counterexample(n):
    """Find a nonempty S with mu(P eta S) != S when mu is intersection."""
    for mask in subsets(n)[1:]:
        singletons = [1 << x for x in members(mask)]
        meet = (1 << n) - 1
        for s in singletons:
            meet &= s
        if meet != mask:
            return mask, meet
    return None

def main():
    print("Maybe monad: algebras on an n-element set")
    for n in range(4):
        count = len(maybe_algebras(n))
        print(f"  n = {n}: {count} algebra(s) among {n ** (n + 1)} maps"
              " Option X -> X")
    print("Power-set monad: algebras a : P(X) -> X found by full search")
    for n in range(1, 4):
        algebras = powerset_algebras(n)
        sups = sum(is_chain(order_of(a, n), n)
                   and is_least_upper_bound_map(a, order_of(a, n), n)
                   for a in algebras)
        print(f"  n = {n}: {len(algebras)} algebra(s); in {sups} of them "
              "a(S) = sup S in a chain")
    magmas = unital_magmas(3)
    algebra = [m for m in magmas if list_algebra_law_holds(*m, 3)]
    assoc = [m for m in magmas if is_associative(m[0], 3)]
    print("List monad: unital operations on {0, 1, 2}")
    print(f"  unital operations:                      {len(magmas)}")
    print(f"  folds obeying the list-algebra laws:    {len(algebra)}")
    print(f"  associative operations (monoids):       {len(assoc)}")
    print(f"  the two collections coincide:           {algebra == assoc}")
    mask, meet = intersection_unit_counterexample(3)
    print("Fake monad: P with mu = intersection instead of union")
    print(f"  S = {members(mask)}: mu(P eta S) = {members(meet)} != S, "
          "so the right unit law fails")
    print()
    print("Epistemic status: exhaustive search over the finite ranges shown "
          "(sets\nwith at most 3 elements; list-algebra laws checked on nested "
          "lists of\nlength at most 2). It agrees with the theorems in the "
          "lesson but proves\nthem only for these cases; the proofs (and the "
          "Lean file) cover all sets.")

if __name__ == "__main__":
    main()
Runs entirely in your browser, in an isolated worker. Nothing is sent to a server.

The second experiment works in the Kleisli category of the distribution monad. It composes Markov kernels using only η\eta and μ\mu (push forward, then average) and compares with matrix multiplication, in exact rational arithmetic; it also checks the tower property, which is the associativity law of the expectation algebra.

Kleisli composition for the distribution monadPythonExact computationExperimental evidenceComputationally tested
"""The distribution monad: Kleisli arrows are Markov kernels.

D X is the set of finitely supported probability distributions on X; the unit
sends x to the point mass at x and the multiplication averages a distribution
of distributions. A Kleisli arrow X -> D Y is a Markov kernel (a stochastic
matrix), and the experiment computes Kleisli composition *from the monad
structure* (push forward, then flatten) and compares it with the product of
stochastic matrices - the Chapman-Kolmogorov equation. It also checks the
Kleisli identity and associativity laws, and that expectation E : D(R) -> R is
an Eilenberg-Moore algebra whose associativity law is the tower property of
conditional expectation. Exact rational arithmetic; random kernels are seeded.
"""

import random
from fractions import Fraction

def unit(x):
    """eta: the point mass at x, as a dict {outcome: probability}."""
    return {x: Fraction(1)}

def flatten(dist_of_dists):
    """mu: average a list of (probability, distribution) pairs."""
    out = {}
    for p, dist in dist_of_dists:
        for y, q in dist.items():
            out[y] = out.get(y, Fraction(0)) + p * q
    return {y: q for y, q in out.items() if q != 0}

def push(dist, kernel):
    """D k: apply a kernel to every outcome, giving a distribution of dists."""
    return [(p, kernel(x)) for x, p in dist.items()]

def kleisli(f, g):
    """Kleisli composite x |-> mu(D g (f x)) of kernels f, then g."""
    return lambda x: flatten(push(f(x), g))

def kernel_from_matrix(matrix):
    """The kernel i |-> row i of a stochastic matrix."""
    return lambda i: {j: p for j, p in enumerate(matrix[i]) if p != 0}

def matrix_from_kernel(kernel, rows, cols):
    """The stochastic matrix of a kernel on {0..rows-1} -> {0..cols-1}."""
    return [[kernel(i).get(j, Fraction(0)) for j in range(cols)]
            for i in range(rows)]

def mat_mul(a, b):
    """Product of matrices with Fraction entries."""
    return [[sum((a[i][k] * b[k][j] for k in range(len(b))), Fraction(0))
             for j in range(len(b[0]))] for i in range(len(a))]

def random_stochastic(rows, cols, rng):
    """A random stochastic matrix with small rational entries."""
    matrix = []
    for _ in range(rows):
        weights = [rng.randint(0, 4) for _ in range(cols)]
        if sum(weights) == 0:
            weights[rng.randrange(cols)] = 1
        total = sum(weights)
        matrix.append([Fraction(w, total) for w in weights])
    return matrix

def expectation(dist):
    """The algebra map E : D(Q) -> Q."""
    return sum((p * x for x, p in dist.items()), Fraction(0))

def tower_property_holds(dist_of_dists):
    """E(D E (P)) == E(mu P): the algebra associativity law for E."""
    outer = {}
    for p, dist in dist_of_dists:
        m = expectation(dist)
        outer[m] = outer.get(m, Fraction(0)) + p
    return expectation(outer) == expectation(flatten(dist_of_dists))

def random_mixture(size, rng):
    """A random distribution (list of weighted pairs) of distributions."""
    out = []
    for p in random_stochastic(1, size, rng)[0]:
        dist = {}
        for q in random_stochastic(1, 3, rng)[0]:
            v = Fraction(rng.randint(-9, 9))
            dist[v] = dist.get(v, Fraction(0)) + q
        out.append((p, dist))
    return out

def run_trials(trials, rng):
    """Count failures of each law on random kernels between small sets."""
    fails = {"matrix": 0, "assoc": 0, "unit": 0, "tower": 0}
    for _ in range(trials):
        a, b, c, d = (rng.randint(1, 4) for _ in range(4))
        m1, m2, m3 = (random_stochastic(a, b, rng),
                      random_stochastic(b, c, rng),
                      random_stochastic(c, d, rng))
        f, g, h = map(kernel_from_matrix, (m1, m2, m3))
        if matrix_from_kernel(kleisli(f, g), a, c) != mat_mul(m1, m2):
            fails["matrix"] += 1
        left = matrix_from_kernel(kleisli(kleisli(f, g), h), a, d)
        right = matrix_from_kernel(kleisli(f, kleisli(g, h)), a, d)
        fails["assoc"] += left != right
        ident = (matrix_from_kernel(kleisli(unit, f), a, b) == m1
                 == matrix_from_kernel(kleisli(f, unit), a, b))
        fails["unit"] += not ident
        fails["tower"] += not tower_property_holds(random_mixture(b, rng))
    return fails

def main():
    rain = [[Fraction(7, 10), Fraction(3, 10)],
            [Fraction(2, 5), Fraction(3, 5)]]
    weather = kernel_from_matrix(rain)
    two_days = matrix_from_kernel(kleisli(weather, weather), 2, 2)
    print("A two-state weather chain (0 = dry, 1 = rainy) as a Kleisli arrow")
    print(f"  one day:   {[[str(p) for p in row] for row in rain]}")
    print(f"  two days via mu . D k . k: "
          f"{[[str(p) for p in row] for row in two_days]}")
    print(f"  equals the matrix square:  {two_days == mat_mul(rain, rain)}")
    rng = random.Random(2024)
    fails = run_trials(200, rng)
    print("200 seeded random kernels between sets of size 1 to 4:")
    print(f"  Kleisli composite != matrix product:     {fails['matrix']}")
    print(f"  associativity failures:                  {fails['assoc']}")
    print(f"  identity-law failures (eta = Dirac):     {fails['unit']}")
    print(f"  tower-property failures for E:           {fails['tower']}")
    print()
    print("Epistemic status: exact rational arithmetic, so each check is a "
          "true\nstatement about the kernels tested; but 200 random cases "
          "are evidence,\nnot proof. The general facts (Kleisli composition "
          "is matrix product,\nE is a D-algebra) follow from linearity, as "
          "the lesson explains.")

if __name__ == "__main__":
    main()
Runs entirely in your browser, in an isolated worker. Nothing is sent to a server.
Exercises

Exercises

1. Monads

Warm-upHuman

The maybe monad on Set\mathbf{Set} has TX=X⊔{⊥}TX = X \sqcup \{\bot\}, ηX(x)=x\eta_X(x) = x, and μX\mu_X collapsing the two copies of ⊥\bot. What is a TT-algebra (A,a)(A, a)?

Choose one

2. Monads

CoreHuman

How many algebra structures a:PA→Aa : \mathcal{P}A \to A for the power-set monad are there on the three-element set A={p,q,r}A = \{p, q, r\}?

3. Monads

Warm-upHuman

In the Kleisli category of the list monad, let f(n)=[n,n+1]f(n) = [n, n + 1] and g(n)=[10n]g(n) = [10n] (both from Z\mathbb{Z} to List(Z)\mathrm{List}(\mathbb{Z})). What is (g∘Tf)(1)=μ(Tg(f(1)))(g \circ_T f)(1) = \mu(Tg(f(1)))?

Choose one

4. Monads

CoreHuman

Let F⊣GF \dashv G with F:C→DF : \mathcal{C} \to \mathcal{D}, unit η\eta and counit ε\varepsilon. The induced monad is T=GFT = GF on C\mathcal{C}. What is its multiplication μX:GFGFX→GFX\mu_X : GFGFX \to GFX?

Choose one

5. Monads

CoreHuman

In proving that ηA\eta_A is a right identity in the Kleisli category, we write, for f:A→TBf : A \to TB,

f∘TηA=μB∘Tf∘ηA=μB∘ηTB∘f=f.f \circ_T \eta_A = \mu_B \circ Tf \circ \eta_A = \mu_B \circ \eta_{TB} \circ f = f.

Which two facts justify the second and third equalities, in order?

Choose one

6. Monads

StretchHuman

For the list monad TT on Set\mathbf{Set}, SetT≃Mon\mathbf{Set}^T \simeq \mathbf{Mon}. Which argument shows that the Kleisli category SetT\mathbf{Set}_T is not equivalent to Mon\mathbf{Mon}?

Choose one

7. Monads

CoreHuman

Which forgetful functors to Set\mathbf{Set} are monadic? (Choose all that apply.)

Choose all that apply

8. Monads

CoreFormal

In the Lean file, a list algebra on X has act : List X → X. Which field states the associativity law a∘Ta=a∘μAa \circ Ta = a \circ \mu_A?

Choose one

9. Monads

StretchComputational

Write kleisli(f, g) returning the Kleisli composite (first f, then g) for the list monad: f and g are Python functions returning lists, and the composite applies g to every output of f and concatenates. Also write unit(x) returning [x]. The tests check the Kleisli category laws on examples.

Runs entirely in your browser, in an isolated worker. Nothing is sent to a server.
Common misconceptionsH

Common misconceptions

Misconception

"Monads come from programming." They arose in algebraic topology and homological algebra: Godement's construction fondamentale (1958) for sheaf cohomology, Huber's observation (1961) that adjunctions yield them, and the work of Eilenberg, Moore, Kleisli and Beck in the 1960s, when they were called standard constructions or triples. Moggi applied them to programming semantics in 1989.

Misconception

"The Kleisli and Eilenberg–Moore categories of a monad are always equivalent." The Kleisli category is the full subcategory of free algebras. It is equivalent to the whole Eilenberg–Moore category only when every algebra is (isomorphic to) a free one — true for the maybe monad, false for the list monad, where the monoid Z/2\Z/2 is not free and has an endomorphism monoid of size 2 that no Kleisli object has.

Misconception

"A monad is just a functor with some maps η\eta and μ\mu." The maps must be natural and satisfy the associativity and both unit laws. The power-set functor with η(x)={x}\eta(x) = \{x\} and μ=⋂\mu = \bigcap satisfies the associativity law and the left unit law, yet it is not a monad: the right unit law fails, and this μ\mu is not even natural.

Misconception

"Every algebra structure is unique / every forgetful functor with a left adjoint is monadic." A set can carry many algebra structures (six power-set algebras on three points). And having a left adjoint is not enough: Top→Set\cat{Top} \to \cat{Set} has one but is not monadic, because it does not reflect isomorphisms.

ViewpointsH

Viewpoints

Topology— Compact spaces as algebras; sheaf resolutions

The ultrafilter monad β\beta on Set\cat{Set} sends XX to the set of ultrafilters on XX (for discrete XX, the Stone–Čech compactification), with η\eta the principal ultrafilters. Manes' theorem (1969): the algebras for β\beta are exactly the compact Hausdorff spaces, the structure map sending each ultrafilter to its unique limit, and algebra morphisms are continuous maps. Compactness says every ultrafilter has a limit, Hausdorffness that it is unique; the algebra laws encode the topology. So a purely algebraic notion recovers a central class of spaces (see point-set topology).

Godement's original monad lives on sheaves: if XδX^\delta is XX with the discrete topology and p:Xδ→Xp : X^\delta \to X the identity map, the adjunction p∗⊣p∗p^* \dashv p_* gives the monad TF(U)=∏x∈UFxT\mathcal{F}(U) = \prod_{x \in U} \mathcal{F}_x of discontinuous sections. Iterating TT with the face maps built from η\eta and μ\mu yields the flabby Godement resolution F→TF→T2F→⋯\mathcal{F} \to T\mathcal{F} \to T^2\mathcal{F} \to \cdots, which computes sheaf cohomology (see sheaves).

Algebra— Varieties, theories and descent

For a variety of algebras (groups, rings, lattices, RR-modules, …) the free-algebra adjunction is monadic, and the monad is finitary (determined by its values on finite sets). Conversely, finitary monads on Set\cat{Set} correspond to Lawvere's algebraic theories (Lawvere 1963; Linton 1966): a monad is a presentation-free description of an equational theory, TXTX being the set of terms in variables XX modulo the equations, η\eta the variables and μ\mu substitution. For a monoid object AA in a monoidal category (a ring in Ab\cat{Ab}, an algebra in Vectk\cat{Vect}_k), A⊗−A \otimes - is a monad whose algebras are the AA-modules.

Dually, Beck's theorem for comonads is the abstract form of Grothendieck's descent. For a faithfully flat homomorphism of commutative rings A→BA \to B, extension of scalars B⊗A−:A-Mod→B-ModB \otimes_A - : A\text{-}\cat{Mod} \to B\text{-}\cat{Mod} is comonadic, and coalgebras for the induced comonad are BB-modules with descent data (Bénabou–Roubaud 1970). This is the algebraic heart of gluing modules and quasi-coherent sheaves along faithfully flat covers in algebraic geometry.

Probability— Kleisli arrows are Markov kernels

For the finite distribution monad DD, Kleisli arrows X→DYX \to DY are Markov kernels and Kleisli composition is the Chapman–Kolmogorov equation P(m+n)=P(m)P(n)P^{(m+n)} = P^{(m)} P^{(n)}; the Kleisli category of DD on finite sets is the category of stochastic matrices. A Markov chain with transition kernel k:X→DXk : X \to DX is an endomorphism in this category, and its nn-step behaviour is the nn-fold Kleisli power (see Markov chains). Expectation is an algebra DR→RD\R \to \R, and its associativity law is the tower property. Lawvere (1962) and Giry (1982) extended this to the Giry monad on measurable spaces, sending XX to the space of probability measures on it; its Kleisli arrows are measurable Markov kernels, and this is now the basis of categorical probability and of the semantics of probabilistic programming (see measure-theoretic probability).

Computation— Effects and the monad laws

In Moggi's semantics a type of computations returning BB is TBTB, return is η\eta and sequencing (>>=, do-notation) is Kleisli extension f∗=μ∘Tff^* = \mu \circ Tf. The monad laws are what make program transformations valid: associativity justifies flattening nested do-blocks; the unit laws justify removing return x >>= f and m >>= return. Different monads give different effects (exceptions, state, nondeterminism, input/output, probability, continuations TB=R(RB)TB = R^{(R^B)}), and monad morphisms translate between them. Later refinements — algebraic effects and handlers (Plotkin and Power; Plotkin and Pretnar) — return to the algebraic view: an effect is given by operations and equations, and its monad is the free-algebra monad of that theory (see formal methods and the λ-calculus).

Logic— Closure, possibility and modalities

On a preorder of propositions ordered by entailment, a monad is a closure operator jj with p⊢jpp \vdash jp and jjp⊢jpjjp \vdash jp. In the modal logic S4, possibility ◊\Diamond satisfies p⊢◊pp \vdash \Diamond p and ◊◊p⊢◊p\Diamond\Diamond p \vdash \Diamond p, so it is a monad (and necessity □\Box a comonad). The modality of lax logic is a monad of this kind, and so are the Lawvere–Tierney topologies of topos theory, which in addition preserve conjunction and classify subtoposes such as categories of sheaves (see elementary topoi).

Category theory— A monoid, one dimension up

Endofunctors of C\mathcal{C} form a strict monoidal category under composition, and a monad is a monoid object in it (μ\mu the multiplication, η\eta the unit). Street's formal theory of monads (1972) defines a monad in any 2-category as a 1-cell t:a→at : a \to a with 2-cells η,μ\eta, \mu satisfying the usual laws; in Cat\cat{Cat} these are the monads of this lesson, and (Bénabou) in the bicategory of spans of sets they are exactly the small categories. Kan extensions give the most general source of monads: every functor GG whose right Kan extension along itself exists has a codensity monad, which for GG a right adjoint is the induced monad (see Kan extensions).

Wonder Trails

Wonder Trails

History & global context

History and global context

  • Roger Godement (France) introduced the "standard construction" in Topologie algébrique et théorie des faisceaux (1958), to build flabby resolutions of sheaves.
  • Peter J. Huber (Switzerland) showed in 1961, in work on homotopy theory in general categories, that every adjunction produces such a construction.
  • In 1965 Heinrich Kleisli (Switzerland) and, independently, Samuel Eilenberg and John C. Moore showed that every monad arises from an adjunction, by the two constructions that now bear their names.
  • Jon Beck proved the monadicity theorem in his 1967 Columbia thesis Triples, algebras and cohomology; F. William Lawvere's 1963 thesis on algebraic theories and Fred Linton's work connected monads to universal algebra; Ernest Manes characterised compact Hausdorff spaces as algebras in 1969. The name "monad" replaced "triple" in the late 1960s and was popularised by Mac Lane's 1971 textbook; it is usually credited to Jean Bénabou.
  • Michèle Giry (1982), building on unpublished notes of Lawvere (1962), introduced the probability monad on measurable spaces.
  • Eugenio Moggi (Italy, 1989 and 1991) used monads to structure the semantics of computational effects; Philip Wadler and Simon Peyton Jones brought them into functional programming, and Haskell adopted monadic input/output in the 1990s.
Further reading

Further reading

  • Saunders Mac Lane, Categories for the Working Mathematician (1971; 2nd edition 1998), Chapter VI — monads, algebras, the comparison theorems and Beck's theorem.
  • Emily Riehl, Category Theory in Context (2016), Chapter 5 — a modern treatment with many examples, including Beck's theorem.
  • Francis Borceux, Handbook of Categorical Algebra 2 (1994), Chapter 4 — monads in depth.
  • Michael Barr and Charles Wells, Toposes, Triples and Theories (1985) — triples, algebraic theories and descent.
  • Eugenio Moggi, "Notions of computation and monads", Information and Computation 93 (1991).
  • Tom Leinster, Basic Category Theory (2014) — for the adjunctions this lesson builds on.