第 17 章:一切都是关于态射(It's All About Morphisms)
原文:Bartosz Milewski, Category Theory for Programmers, Scala Edition, Chapter 17. 原书 PDF、
.tex源文件及相关图像采用 CC BY-SA 4.0;本译文按同一许可发布。
如果到现在我还没说服你:范畴论全都关乎态射,那我就没有把工作做好。由于下一主题是伴随,而伴随是用 hom-set 的同构来定义的,所以回顾一下我们对 hom-set 构件的直觉是有意义的。另外,你会看到伴随提供了一种更一般的语言,可以描述我们之前研究过的许多构造,因此回顾这些构造也会有所帮助。
17.1 函子(Functors)
首先,你真的应该把函子看作态射的映射。Haskell 中 Functor 类型类的定义强调的正是这种看法,因为它围绕 fmap 展开。当然,函子也映射对象,也就是态射的端点;否则我们就无法谈论保持组合。对象告诉我们哪些态射对可以组合。一个态射的目标必须等于另一个态射的源,它们才能被组合。因此,如果我们希望态射组合被映射为提升后态射的组合,那么端点的映射基本上也就被确定了。
17.2 交换图(Commuting Diagrams)
态射的许多性质都用交换图表达。如果某个特定态射可以用不止一种方式表示为其他态射的组合,那么我们就有一个交换图。
特别是,交换图构成了几乎所有通用构造的基础(始对象和终对象是值得注意的例外)。我们在积、余积、各种其他(余)极限、指数对象、自由幺半群等定义中都见过这一点。
积是通用构造的一个简单例子。我们选择两个对象 $a$ 和 $b$,并观察是否存在一个对象 $c$,以及一对态射 $p$ 和 $q$,使它具有成为它们的积的通用性质。

积是极限的特殊情形。极限用锥定义。一般的锥由交换图构成。这些图的交换性可以被函子映射的合适自然性条件替代。这样,交换性就被降格为自然变换这种高级语言之下的汇编语言。
17.3 自然变换(Natural Transformations)
一般来说,只要我们需要从态射到交换方块的映射,自然变换就非常方便。自然性方块中相对的两边,是某个态射 $f$ 在两个函子 $F$ 和 $G$ 下的映射。另外两边是自然变换的分量(它们也都是态射)。

自然性意味着,当你移动到“相邻”分量时(所谓相邻,是指通过态射连接),你并没有违背范畴或函子的结构。你先用自然变换的一个分量跨越对象之间的间隙,再用函子跳到它的邻居;或者反过来,结果都无关紧要。这两个方向是正交的。可以说,自然变换让你左右移动,而函子让你上下移动或前后移动。你可以把一个函子的像想象成目标范畴中的一张片层。自然变换把对应于 $F$ 的这样一张片层映射到对应于 $G$ 的另一张片层。

我们在 Haskell 中见过这种正交性的例子。在那里,函子的作用会修改容器的内容而不改变其形状,而自然变换会把未改动的内容重新包装到另一个容器中。这些操作的顺序并不重要。
我们还见过,在极限的定义中,锥被自然变换替代。自然性确保每个锥的边都交换。不过,极限仍然是用锥之间的映射定义的。这些映射也必须满足交换性条件。(例如,积定义中的三角形必须交换。)
这些条件同样也可以被自然性替代。你可能还记得,通用锥,或者说极限,被定义为下面两个函子之间的自然变换。第一个是(逆变)hom 函子:
F :: c -> C(c, Lim D)
第二个是(同样逆变的)函子,它把 $C$ 中对象映射为锥,而锥本身又是自然变换:
G :: c -> Nat(Delta c, D)
这里,$\Delta c$ 是常函子,$D$ 是定义 $C$ 中图示的函子。函子 $F$ 和 $G$ 在 $C$ 的态射上都有良好定义的作用。碰巧,这两个函子之间的这个特定自然变换是一个同构。
17.4 自然同构(Natural Isomorphisms)
自然同构,也就是每个分量都可逆的自然变换,是范畴论表达“两个东西相同”的方式。这样的变换的每个分量都必须是对象之间的同构,也就是具有逆的态射。如果把函子的像想象成片层,自然同构就是这些片层之间一一对应且可逆的映射。
17.5 Hom-Set
但态射是什么?它们确实比对象拥有更多结构:不同于对象,态射有两个端点。但如果固定源对象和目标对象,二者之间的态射就形成一个乏味的集合(至少对局部小范畴而言如此)。我们可以给这个集合中的元素起名,比如 $f$ 或 $g$,以便彼此区分;但究竟是什么让它们不同?
给定 hom-set 中态射之间的本质差异,在于它们与其他态射(来自相邻 hom-set)组合的方式。如果存在一个态射 $h$,它与 $f$ 的组合(无论是预组合还是后组合)不同于它与 $g$ 的组合,例如:
h . f != h . g
那么我们就能直接“观察”到 $f$ 和 $g$ 之间的差别。但即使这种差别不能直接观察到,也可以使用函子放大 hom-set。函子 $F$ 可能把两个态射映射为不同态射:
F f != F g
而且是在一个更丰富的范畴中;在那里,相邻 hom-set 提供了更高分辨率,例如:
h' . F f != h' . F g
其中 $h'$ 不在 $F$ 的像中。
17.6 Hom-Set 同构(Hom-Set Isomorphisms)
许多范畴构造都依赖 hom-set 之间的同构。但由于 hom-set 只是集合,它们之间的普通同构并不能告诉你太多。对有限集合而言,一个同构只说明它们元素个数相同。如果集合是无限的,那么它们的基数必须相同。但任何有意义的 hom-set 同构都必须考虑组合。而组合涉及不止一个 hom-set。我们需要定义跨越整个 hom-set 族的同构,并施加某些与组合协作的兼容条件。自然同构正好符合这个要求。
但 hom-set 的自然同构是什么?自然性是函子之间映射的性质,而不是集合之间映射的性质。所以我们真正谈论的是 hom-set 值函子之间的自然同构。这些函子不只是集合值函子。它们在态射上的作用由相应的 hom 函子诱导。态射由 hom 函子通过预组合或后组合(取决于函子的协变性)被规范地映射。
Yoneda 嵌入就是这样一种同构的例子。它把 $C$ 中的 hom-set 映射到函子范畴中的 hom-set,并且这个映射是自然的。Yoneda 嵌入中的一个函子是 $C$ 中的 hom 函子,另一个函子把对象映射为 hom-set 之间自然变换的集合。
极限的定义也是 hom-set 之间的自然同构(第二个 hom-set 同样位于函子范畴中):
C(c, Lim D) ~= Nat(Delta c, D)
事实证明,我们对指数对象的构造,或者对自由幺半群的构造,也都可以重写成 hom-set 之间的自然同构。
这并非巧合。接下来我们会看到,它们只是伴随的不同例子,而伴随正是被定义为 hom-set 的自然同构。
17.7 Hom-Set 的非对称性(Asymmetry of Hom-Sets)
还有一个观察会帮助我们理解伴随。一般来说,hom-set 并不对称。hom-set $C(a, b)$ 往往与 hom-set $C(b, a)$ 非常不同。把偏序看成范畴,是这种非对称性的终极展示。在偏序中,从 $a$ 到 $b$ 的态射存在,当且仅当 $a$ 小于等于 $b$。如果 $a$ 和 $b$ 不同,就不可能有从 $b$ 到 $a$ 的反向态射。所以,如果 hom-set $C(a, b)$ 非空,在这种情况下意味着它是一个单元素集合,那么除非 $a = b$,否则 $C(b, a)$ 必须为空。这个范畴中的箭头有明确的单向流动。
预序基于不一定反对称的关系,它也“基本上”有方向性,只是偶尔有环。
把任意范畴看作预序的一种推广,是很方便的。
预序是薄范畴,也就是所有 hom-set 要么是单元素集合,要么为空。我们可以把一般范畴想象成“厚”的预序。
17.8 挑战(Challenges)
- 考虑自然性条件的一些退化情形,并画出相应图示。例如,如果函子 $F$ 或 $G$ 把对象 $a$ 和 $b$(态射 $f : a \to b$ 的两端)都映射到同一个对象,会发生什么,例如 $F a = F b$ 或 $G a = G b$?(注意,这样会得到一个锥或余锥。)然后考虑 $F a = G a$ 或 $F b = G b$ 的情形。最后,如果从一个自环态射开始,也就是 $f : a \to a$,又会怎样?