Haskell中的Profunctor装备

Hacker News Top 工具

摘要

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

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

缓存时间: 2026/05/18 06:53

# Haskell 中的 Profunctor 设备 来源:https://bartoszmilewski.com/2026/05/16/profunctor-equipment-in-haskell/ 此前:Profunctor 设备 (https://bartoszmilewski.com/2026/04/24/profunctor-equipment/) 为了让程序员更容易理解,我决定在 Haskell 中提供一些设备的玩具实现。这种编码的优势在于编译器可以验证它,而我仍然更信任编译器而不是 AI。 更充分的实现需要完整的依赖类型语言,但如果我们将自己限制在单个范畴内,仅使用内函子和内 Profunctor,我们至少可以获得一些直觉。如果你想看到更详尽的版本,请参阅 Sjoerd Visscher 的 `proarrows` (https://github.com/sjoerdvisscher/proarrow/) 库。 我将使用的唯一 0-胞腔是类型与函数的 Haskell 范畴。对于垂直 1-胞腔,我将使用标准库中的 `Functor` 实现;对于水平 1-胞腔,我将使用 `Profunctor`。 在 \(\mathbb{P}rof\) 中的 2-胞腔: [](https://i0.wp.com/bartoszmilewski.com/wp-content/uploads/2026/04/Screenshot-2026-04-18-at-16.48.46.png?ssl=1) 实现为一个自然变换: ``` type Cell f g h j = forall a c . h a c -> j (f a) (g c) ``` 这里的 `forall` 充当全称量词。 此类胞腔的水平组合由下式给出: ``` hcomp :: (Functor f, Functor f', Functor g, Functor g' , Profunctor h, Profunctor j, Profunctor k) => Cell f g h j -> Cell f' g' j k -> Cell (Compose f' f) (Compose g' g) h k hcomp fg_hj fg_jk hac = dimap getCompose Compose $ fg_jk (fg_hj hac) ``` 我使用了库中定义的函子组合: ``` newtype Compose f g a = Compose { getCompose :: f (g a) } ``` 胞腔的垂直组合使用了更复杂的 Profunctor 组合: ``` vcomp :: (Functor f, Functor g, Functor h , Profunctor p, Profunctor q, Profunctor r, Profunctor s) => Cell f g p r -> Cell g h q s -> Cell f h (Procompose q p) (Procompose s r) vcomp fg_pr gh_qs (Procompose qxc pax) = Procompose (gh_qs qxc) (fg_pr pax) ``` Profunctor 组合使用 coend 定义。在 Haskell 中,我们将 coend: \[ \int^x P \langle x, c\rangle \times Q \langle d, x \rangle \] 实现为存在类型: ``` data Procompose p q d c where Procompose :: p x c -> q d x -> Procompose p q d c ``` 这里,`x` 是不在参数列表中的类型,因此它使用全称量词的存在对应形式解释。 这是水平单位胞腔: ``` type Hunit p = Cell Identity Identity p p hUnit :: Profunctor p => Hunit p hUnit = dimap runIdentity Identity ``` 以及其垂直对应物: ``` type Vunit f a b = Cell f f (->) (->) vUnit :: Functor f => Vunit f a b vUnit = fmap ``` 我使用了库中的 `Identity` 函子实现,以及类型构造器 `(->)` 作为同态 Profunctor——Profunctor 组合的单位。单位律满足同构。 陪伴(companion)和共轭(conjoint)是库类型 `Costar` 和 `Star` 的同义词: ``` newtype Star f d c = Star { runStar :: d -> f c } newtype Costar f d c = Costar { runCostar :: f d -> c } ``` ``` type Companion f d c = Costar f d c type Conjoint f d c = Star f d c ``` 陪伴的单位和余单位胞腔: [](https://i0.wp.com/bartoszmilewski.com/wp-content/uploads/2026/04/Screenshot-2026-04-19-at-19.15.45.png?ssl=1) 分别由下式给出: ``` type CompUnit f = Cell Identity f (->) (Costar f) compUnit :: Functor f => CompUnit f compUnit h = Costar (fmap (h . runIdentity)) ``` 以及: ``` type CompCoUnit f = Cell f Identity (Costar f) (->) compCoUnit :: Functor f => CompCoUnit f compCoUnit (Costar h) = Identity . h ``` 类似地,对于共轭: [](https://i0.wp.com/bartoszmilewski.com/wp-content/uploads/2026/04/Screenshot-2026-04-19-at-21.59.56.png?ssl=1) ``` type ConjUnit f = Cell f Identity (->) (Star f) conjUnit :: Functor f => ConjUnit f conjUnit h = Star (fmap (Identity . h)) ``` 以及: ``` type ConjCoUnit f = Cell Identity f (Star f) (->) conjCoUnit :: Functor f => ConjCoUnit f conjCoUnit (Star h) = h . runIdentity ``` 更高级的构造需要定义 Hask 内部的范畴并使用依赖类型。 Haskell 代码可在此处 (https://v15.next.forgejo.org/BartoszMilewski/Categories/src/branch/main/Equipment.hs) 获取。

相似文章

余代数和自动机

Lobsters Hottest

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

Data types à la carte (2008)

Lobsters Hottest

本文提出了一种从独立组件组合数据类型和函数的技术,并将该方法扩展到结合自由单子,从而实现了对Haskell的IO单子的模块化结构。

Effectful 递归方案

Lobsters Hottest

《Effekt》编程语言博客文章演示了如何利用效应和处理器实现递归方案(特别是 catamorphisms),以此取代传统的基于函子的方法,从而避免了对无限递归类型的依赖。

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

Hacker News Top

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

代数效应:给普通人的解释

Hacker News Top

这是一篇教育性博客文章,通过类比 try/catch 和 async/await 来解释编程中的代数效应概念,并讨论了它们与 React 及未来编程范式的潜在关联。