Actegories

Hacker News Top 工具

摘要

一篇解释范畴论中Actegories概念及其在编程光学(如lenses和prisms)中作用的文章,并包含Haskell实现。

暂无内容
查看原文
查看缓存全文

缓存时间: 2026/07/14 13:17

# 作用范畴 来源:https://bartoszmilewski.com/2026/06/30/actegories/ 前文:双范畴中的Kan扩张(https://bartoszmilewski.com/2026/06/13/kan-extensions-in-double-categories/) 在编程中,作用范畴在光学(透镜、棱镜、遍历等)中扮演着核心角色。要理解作用范畴,我们先从幺半范畴的定义开始。 ## 幺半范畴 一个幺半范畴 \(\mathbf M\) 是装备了张量积的范畴。张量积是一个函子 \(\otimes \colon \mathbf M \times \mathbf M \to \mathbf M\)。我们假定这个乘积是结合的且具有单位——在同构意义下。这意味着存在一个可逆的结合子: \[\alpha_{a, b, c} \colon (a \otimes b) \otimes c \to a \otimes (b \otimes c)\] 关于所有三个参数自然。我们还有一个单位对象 \(1\) 和两个(可逆、自然)的单位子: \[\lambda_a \colon 1 \otimes a \to a\] \[\rho_a \colon a \otimes 1 \to a\] 为了更好地理解,我们尝试在 Haskell 中建模幺半范畴。我们通过张量积的类型 `ten` 进行参数化,我们希望它是一个 `Bifunctor`: ```haskell class (Bifunctor ten) => Monoidal ten where ``` 定义 Hask 的子范畴的标准方法是通过施加约束来限制对象的类型。这种限制具有特殊的种类,`Constraint`: ```haskell type Obj :: Type -> Constraint ``` 这种约束的一个常见例子是类型类。例如,`Monoid` 将范畴的对象限制为幺半群。(原则上,我们也应该限制箭头的类型,这里限制为幺半群同态。) 我们可以将幺半范畴的单位指定为关联类型(通过 `ten` 参数化): ```haskell type Unit ten :: Type ``` 单位应该是范畴的对象,因此它应该满足约束。我们可以在定义中将其编码为先决条件:`obj (Unit ten)`。这会导致循环,我们可以使用语言编译指令 `UndecidableSuperClasses` 来克服: ```haskell class (Obj (Unit ten), Bifunctor ten) => Monoidal ten where type Unit ten :: Type unitObj :: Obj (Unit ten) associator :: (Obj a, Obj b, Obj c) => (a `ten` b) `ten` c -> a `ten` (b `ten` c) associatorInv :: (Obj a, Obj b, Obj c) => a `ten` (b `ten` c) -> (a `ten` b) `ten` c leftUnitor :: Obj a => Unit ten `ten` a -> a leftUnitorInv :: Obj a => a -> Unit ten `ten` a rightUnitor :: Obj a => a `ten` Unit ten -> a rightUnitorInv :: Obj a => a -> a `ten` Unit ten ``` 注意这些函数类型中的 `obj` 约束以及张量的中缀表示法。 让我们来看几个例子。最简单的是以笛卡尔积为张量的所有类型的范畴。我们使用一个空类来定义 `Hask`,并使所有对象成为其实例: ```haskell class Hask a instance Hask a ``` 类似地,我们可以定义以 `Either` 为张量积的幺半范畴,或以 `Monoid` 为对象约束的幺半范畴。 ## 作用范畴 作用范畴是支持幺半范畴作用的范畴。可以将其想象为用幺半范畴的对象“乘”或“缩放”该范畴的对象。(左)作用可以定义为从乘积范畴到 C 的函子: \[\triangleright \colon \mathbf M \times C \to C\] 或者,经过柯里化后,作为从 \(\mathbf M\) 到自函子范畴的函子: ![\triangleright \colon \mathbf M \to [C, C]](https://s0.wp.com/latex.php?latex=%5Ctriangleright+%5Ccolon+%5Cmathbf+M+%5Cto+%5BC%2C+C%5D&bg=ffffff&fg=29303b&s=0&c=20201002) 一致性条件是连接作用 \(\triangleright\) 与张量积 \(\otimes\) 及其单位 \(1\) 的可逆自然变换: \[\alpha_{m n a} \colon (m \otimes n) \triangleright a \to m \triangleright (n \triangleright a)\] \[\lambda_{a} \colon 1 \triangleright a \to a\] 作用在两个参数上都是函子性的,因此为简单起见,我们的 Haskell 翻译将其固定为 `Bifunctor`。(`Profunctor` 作用也是可能的。从范畴论的角度看,它对应使用 \(\mathbf M^{op}\) 作为幺半范畴。) ```haskell class (Bifunctor act, Monoidal ten) => Actegory act ten | act -> ten where act :: act m a -> a ``` 另一个简化的假设是作用唯一标识张量积,这里编码为函数依赖 `act -> ten`。 作用范畴的最简单例子是笛卡尔积的自作用。这里,幺半范畴作用于自身: ```haskell instance Actegory (,) (,) where act = ... ``` ## 幺半函子 使用相同幺半范畴进行作用的范畴构成一个范畴。该范畴中的态射是(严格)幺半函子。这些函子将一个作用映射到另一个作用: \[f (m \triangleright_1 a) \cong m \triangleright_2 f a\] 在 Haskell 中,我们可以将其建模为: ```haskell class (Actegory act1 ten, Actegory act2 ten) => MonoidalFunctor f ten act1 act2 where ``` 事实上,作用范畴构成一个双范畴,其中保持作用的自然变换作用在幺半函子之间。 这里有一个有趣的例子,展示了非平凡作用范畴之间的幺半函子: ```haskell instance MonoidalFunctor (Map String) (,) (,) (,) where ``` Haskell 代码可见[此处](https://v15.next.forgejo.org/BartoszMilewski/Categories/src/branch/main/src/Actegory.hs)。

相似文章

Tambara装备

Hacker News Top

本文解释了范畴论中的Tambara模块,它们与幺半群函子和profunctor光学的关系,并使用Haskell代码说明这些概念,内容基于Mateusz Stroiński近期的一篇论文。

Haskell中的Profunctor装备

Hacker News Top

这篇博客文章提供了一个用Haskell实现的Profunctor装备的玩具实现,包括自然变换和组合,旨在让范畴论概念对程序员来说更易于理解。

应用范畴论课程 (2018)

Hacker News Top

由John Baez教授的应用范畴论在线课程,基于《Seven Sketches in Compositionality》一书,通过一系列讲义涵盖了有序集、资源理论和数据库。

余代数和自动机

Lobsters Hottest

一份介绍性的 literate Haskell 文档,探讨余代数和自动机之间的关系,展示如何利用范畴论中的 fold 和 unfold 操作来建模状态机。

使用Rust和范畴论构建机器学习框架

Hacker News Top

这篇文章宣布了一份工作草稿书籍《Category Theory for Tiny ML in Rust》以及一个公开工作坊,介绍一个使用Rust和范畴论的微型机器学习流水线,旨在通过类型化转换使机器学习结构变得明确。