Tambara Equipment

ibobev1 pts0 comments

Tambara Equipment |   Bartosz Milewski's Programming Cafe

Home

About

Bartosz Milewski's Programming Cafe

Category Theory, Haskell, Concurrency, C++

July 11, 2026

Tambara Equipment

Posted by Bartosz Milewski under Category Theory, Double category | Tags: Category Theory, Double Categories, Optics, Proarrow Equipment, Profunctors, Tambara Modules |

[2] Comments

I was originally attracted to category theory when trying to understand Haskell optics. I was puzzled by the van Laarhoven’s functor representations and Kmett’s use of Tambara modules. By playing Tetris with the Yoneda lemma I was able to make some progress, attacking more and more esoteric topics. With a group of researcher and students at the Oxford Adjoint School in Applied Category Theory we cracked the problem of traversal optics and published a paper summarizing the advances in profunctor optics.

Optics sit at an intersection of monoidal actions and Tambara modules. There is a duality between optics and Tambara representations. It is related to what mathematicians call Tannakian reconstruction, when an algebraic object is recovered from the totality of its representations.

No wonder then that a recent article by Mateusz Stroiński, Module categories, internal bimodules and Tambara modules, piqued my interest. It turns out that Tambara modules can be thought of as horizontal arrows in a double category, which is also a proarrow equipment. I will try to sketch the contents of this paper and illustrate it using Haskell code.

The slogan is that Tambara modules are to monoidal functors as profunctors are to functors.

The main advantage of the double-categorical setting for Tambara modules is that it works out of the box for enriched categories.

Monoidal functors redux

For simplicity, I’ll be using a simplified version of a strict monoidal functor, which omits the object constraint from the definition of a monoidal category:

class (Actegory ten act1, Actegory ten act2, Functor f) =><br>MonFunctor ten act1 act2 f where<br>alpha :: m `act2` f a -> f (m `act1` a)<br>alpha' :: f (m `act1` a) -> m `act2` f a

Here, alpha' is the inverse of alpha.

Monoidal functors compose:

newtype MonFunCompose f g a =<br>MonFunCompose { getMonFunCompose :: f (g a) }

and the composition is again a monoidal functor:

instance ( Actegory ten act1<br>, Actegory ten act2<br>, Actegory ten act3<br>, MonFunctor ten act2 act3 f<br>, MonFunctor ten act1 act2 g)<br>=> MonFunctor ten act1 act3 (MonFunCompose f g)<br>where<br>alpha mfga =<br>let m3fga' = second getMonFunCompose mfga<br>fmga = alpha @ten @act2 @act3 m3fga'<br>fgma = fmap (alpha @ten @act1 @act2) fmga<br>in MonFunCompose fgma

alpha' (MonFunCompose fgma) =<br>let fmga = fmap (alpha' @ten @act1 @act2) fgma<br>mfga = alpha' @ten @act2 @act3 fmga<br>in second MonFunCompose mfga

Notice the use of type application to help the Haskell type checker.

Tambara modules

A Tambara module is a profunctor that is compatible with the action of a monoidal category. If you interpret a profunctor as a proof-relevant relation, a Tambara module has the property that, whenever two objects are related, they remain related when you "multiply" them by the same object . Multiplication in this case means the action of a monoidal category . In other words, a Tambara module is a profunctor equipped with the transformation:

that is natural in and , and dinatural in . The action interacts nicely with the monoidal structure:

(modulo some associators and unitors).

We can illustrate this in Haskell as a typeclass:

class (Actegory ten act, Profunctor j)<br>=> Tambara ten act j where<br>leftAct :: j a b -> j (m `act` a) (m `act` b)

I chose to concentrate on the left action of the actegory, but it’s easy to define the right action, or both. For simplicity, I’m using the same action for both arguments. In full generality, we would have two separate actegories.

The simplest example of a Tambara module is the hom-functor:

instance (Actegory ten act) => Tambara ten act (->) where<br>leftAct :: Actegory ten act => (a -> b) -> m `act` a -> m `act` b<br>leftAct = second

Here I used the bifunctoriality of the action.

Tambara modules form a category, in which action-preserving natural transformations act as morphisms.

The usual profunctor composition using coends also works on Tambara modules.

data TamCompose p q d c where<br>TamCompose :: p x c -> q d x -> TamCompose p q d c

The result of composition is again a Tambara module:

instance (Tambara ten act p, Tambara ten act q)<br>=> Tambara ten act (TamCompose p q) where<br>leftAct :: (Tambara ten act p, Tambara ten act q) =><br>TamCompose p q a b -> TamCompose p q (m `act` a) (m `act` b)<br>leftAct (TamCompose pxc qdx)<br>= TamCompose (leftAct pxc) (leftAct qdx)

Taken together, we have a bicategory , where actegories are 0-cells, Tambara modules with coend composition are 1-cells, and natural transformations between them are 2-cells.

Moreover, endo-Tambara modules, that is Tambara modules that operate within a single category, form a monoidal bicategory, with...

tambara modules category monoidal act2 alpha

Related Articles