---
layout: default
file: "src/Setoid/Categories/Adjunction.lagda.md"
title: "Setoid.Categories.Adjunction module"
date: "2026-06-10"
author: "the agda-algebras development team"
---
### Adjunctions between minimal categories
This is the [Setoid.Categories.Adjunction][] module of the [Agda Universal Algebra Library][].
An `Adjunction L R` exhibits the functor `L : π β π` as *left adjoint* to
`R : π β π`. As adjunctions are a central organizing concept, it's worth pausing to
understand exactly how they are used and what they are for. The recurring situation
in algebra is a pair of translations running in opposite directions β a "free"
construction `L` and a "forgetful" one `R` β such that `L` provides the "most
economical" solution in π to a problem posed in π.
A classical adjunction that appears in this library in
[Classical.Categories.AdjoinUnit][] is the following:
+ the forgetful functor `R` reduces a monoid to a semigroup;
+ the expansion functor `L` freely adjoins a unit to a semigroup;
+ the adjunction is the precise statement that `L πΊ` is the universal monoid
generated by the semigroup `πΊ`.
The last item means that each semigroup homomorphism from `πΊ` into (the underlying
semigroup of) a monoid, any monoid, `π΄` extends uniquely to a monoid homomorphism
`L πΊ β π΄`.
Following the architecture design record [ADR-006][], the `Adjunction`{.AgdaRecord}
record presents this with unit and counit, *componentwise*, that is, a family `unit`
of π-morphisms `A β R (L A)` and a family `counit` of π-morphisms `L (R B) β B`,
each with its naturality square.
The two families have direct readings.
+ `unit A : A β R (L A)` embeds `A` into (the underlying-π-object of) its free
object; "every generator is an element of the free thing it generates;" for
`adjoinUnit β£ forgetUnit` the unit is the inclusion `just`.
+ `counit B : L (R B) β B` *evaluates*: build the free object on something that
already was a π-object and there is a canonical map collapsing the formal
structure back onto the real one; for `adjoinUnit β£ forgetUnit` the counit sends
the freshly adjoined unit to the `Ξ΅` of `B`.
The two *triangle identities* `zig` and `zag` say the unit and counit are inverse
*up to one application of `L` or `R`*.
```text
L (unit A) unit (R B)
L A βββββββββ L (R (L A)) R B βββββββββ R (L (R B))
β² β β² β
β² β β² β
id β² β counit id β² β R (counit B)
β² β (L A) β² β
β² β β² β
β² β β² β
β² β β² β
β β β β
L A R B
```
The following two coherences are what entitle one to call `L` *the* free
construction rather than merely *a* section of `R`:[^1]
+ `zig` (left): embed the generators of `L A` and then evaluate to get `L A` back.
+ `zag` (right): embed `R B` into the free object over it and then evaluate inside
`R` to get `R B` back.
Every law is stated against the owning category's hom-equality `_β_`, so an
instance whose hom-equality is pointwise (the algebra categories of
[Setoid.Categories.Algebra][]) proves the triangles pointwise, with no funext.[^2]
<!--
```agda
{-# OPTIONS --cubical-compatible --exact-split --safe #-}
module Setoid.Categories.Adjunction where
open import Agda.Primitive using ( _β_ ) renaming ( Set to Type )
open import Level using ( Level )
open import Setoid.Categories.Category using ( Category )
open import Setoid.Categories.Functor using ( Functor ; idF ; _βF_ )
open import Setoid.Categories.NaturalTransformation using ( NaturalTransformation )
private variable o β e oβ² ββ² eβ² : Level
```
-->
```agda
record Adjunction
{π : Category o β e} {π : Category oβ² ββ² eβ²}
(L : Functor π π) (R : Functor π π) : Type (o β β β e β oβ² β ββ² β eβ²) where
open Category π renaming ( Obj to πβ; Hom to π[_,_]; _β_ to _βα΅α΅α΅_; id to idα΅α΅α΅; _β_ to _βα΅α΅α΅_ )
open Category π renaming ( Obj to πβ; Hom to π[_,_]; _β_ to _βαΆα΅α΅_; id to idαΆα΅α΅; _β_ to _βαΆα΅α΅_ )
open Functor L using () renaming ( Fβ to Lβ ; Fβ to Lβ )
open Functor R using () renaming ( Fβ to Rβ ; Fβ to Rβ )
field
unit : (A : πβ) β π[ A , Rβ (Lβ A) ]
counit : (B : πβ) β π[ Lβ (Rβ B) , B ]
Ξ· = unit
Ξ΅ = counit
field
unit-natural : {A B : πβ} (f : π[ A , B ]) β unit B βα΅α΅α΅ f βα΅α΅α΅ Rβ (Lβ f) βα΅α΅α΅ unit A
counit-natural : {A B : πβ} (g : π[ A , B ]) β counit B βαΆα΅α΅ Lβ (Rβ g) βαΆα΅α΅ g βαΆα΅α΅ counit A
zig : (A : πβ) β counit (Lβ A) βαΆα΅α΅ Lβ (unit A) βαΆα΅α΅ idαΆα΅α΅ {Lβ A}
zag : (B : πβ) β Rβ (counit B) βα΅α΅α΅ unit (Rβ B) βα΅α΅α΅ idα΅α΅α΅ {Rβ B}
unitNT : NaturalTransformation (idF {π = π}) (R βF L)
unitNT = record { component = unit ; natural = unit-natural }
counitNT : NaturalTransformation (L βF R) (idF {π = π})
counitNT = record { component = counit ; natural = counit-natural }
```
The derived members `unitNT` and `counitNT` repackage the componentwise data as
[`NaturalTransformation`][Setoid.Categories.NaturalTransformation] records; `unitNT` is
the unit natural transformation from the identity functor to the composite `R βF L`;
`counitNT` is the counit natural transformation from `L βF R` to the identity.
Note there is nothing to prove: the naturality squares demanded by the records are
*definitionally* the `unit-natural` and `counit-natural` fields.
The composite `R βF L`, equipped with `unitNT` as its unit, is in fact a monad on π,
with multiplication `Rβ (counit (Lβ A))`; that classical theorem is `adjunctionβmonad` in
[Setoid.Categories.Monad][].
--------------------------------------
[^1]: The design note [m4-5d-free-expansion.md](docs/notes/m4-5d-free-expansion.md) develops that contrast (a section chooses, an adjoint adjoins) at length.
[^2]: The natural-transformation record this footnote once deferred to M4-5e now exists ([Setoid.Categories.NaturalTransformation][]), and `unitNT` / `counitNT` below provide the bundled views. The componentwise fields remain the canonical form, both because they are what the free-expansion spike of M4-5d consumes and because componentwise data is what concrete instances can supply pointwise without funext.
[ADR-006]: docs/adr/006-signature-morphism-category.md