程序设计中的范畴论 (第一部分)

文章目录

  • 程序设计中的范畴论 (第一部分)
    • 0 引言
      • 0.1 抽象
      • 0.2 悖论
    • 1 范畴 (Category)
      • 1.1 交换图
      • 1.2 示例
        • 正整数与偏序关系
        • 矩阵范畴 (向量空间范畴的特例)
        • 实数范畴1 (群范畴的特例)
        • 实数范畴2 (环范畴的特例)
        • 集合范畴
        • 数理逻辑范畴
        • Lua语言范畴 弱类型语言范畴
        • C语言范畴 强类型语言范畴
        • 优雅语言范畴
    • 2 函子 (Functor)
      • 2.1 拟等函子
        • 钩子函子
      • 2.2 忘却函子
      • 2.3 可逆函子
        • 空化函子 (Nullable) 非空化函子 (NonNullable)
        • 捕获函子 (Catching) 抛出函子 (Throwing)
        • 惰化函子 (Lazy)
        • 异步函子 (Async) 同步函子 (Sync)
      • 2.4 拟逆函子
        • 迭代函子 (ForEach)
          • 迭代函子的拟逆函子
          • 迭代范畴的自函子
      • 2.5 映射函子 (Map)
      • 2.6 自函子 (Endofunctor) 单子 (monad)

  范畴论是极其抽象的概念, 为了解释这个概念, 下文中会频繁举例, 甚至嵌套地举例, 因此要分清每段所说的"例如", 是前述哪个"例如"中的"例如".

0 引言

0.1 抽象

  一般来说, 我们的一些观念, 特别是数学观念会是基于构造的.
  比如, 我们有时候会讨论数字 111 是什么, 我们往往会想去构造一个东西, 使其行为表现恰好与1相同. 比如定义 0={∅}0=\{\varnothing\}0={∅}, 1={{∅},∅}1=\{\{\varnothing\}, \varnothing\}1={{∅},∅} 等. 这是一种基于构造的思想.
  但实际上我们在考虑数字的时候会去想他的具体构造, 或者说底层实现吗, 答案是不会的. 我们实际上的对数字的思考只会停留在 111 就是 111, 其具体构造根本不重要.
  事实上数字 111 之所以是数字 111, 并不是因为什么所谓的数学上定义 1={{∅},∅}1=\{\{\varnothing\}, \varnothing\}1={{∅},∅}, 而是因为数字 111 与现实生活中很多常见的一些结构的"形状"相同. 例如在计数的时候, 我们会把一只羊视作 111, 两只羊视作 222 等等, 这样羊在羊群中的合并与数字在数学上的加法具有完全相同的"形状". 再例如我们会把一个苹果视作 111, 两个苹果视作 222 等等, 这样苹果的合并与数字在数学上的加法也具有完全相同的"形状". 这样所谓的"形状"的相同, 在数学上称为同构.
  换而言之, 111 之所以为 111, 就是因为 111 忽略了他的底层实现细节, 只保留了他的功能, 我们无须关心这个 111 到底是一只羊, 还是一个苹果, 抑或是一个集合论的构造 {{∅},∅}\{\{\varnothing\}, \varnothing\}{{∅},∅}. 我们只需关心 111 他具有与另一个数相加的功能.
  数学不是一个具体的对象, 他是一个模板, 任何与其同构(即所谓"形状"相同)的东西, 都可以往里面套, 甚至包括数学他自己. 并且在数学领域内取得的一切成果都可以反馈到与之同构的一切事物上.
  在程序设计中, 类似这样忽略底层实现细节的现象则更多. 比如我们有时候会考虑一个读取文件的函数String fread(File), 他接受一个File对象, 并返回一个String, 他的功能是从File对象描述的文件里读取内容, 并返回一个String表示的内容. 作为用户, 我们只会考虑如何使用这个函数, 去和其他业务函数组合, 期间完全忽略这个函数的底层实现细节. 若是作为平台开发者, 我们才会考虑这个函数的具体实现.
  人类单次思考的概念范围是有限的, 因此我们需要对事物进行抽象, 以忽略掉其底层实现细节, 以将我们有限的精力, 投入到更有意义的高层概念中. 这就是抽象的开端.

0.2 悖论

  有时候我们会讨论所有的集合, 并会去尝试构造一个包括所有集合的集合. 注意, 这种操作会导致悖论.

  • 罗素悖论

设有 S={x∣x∉S}S=\{x|x\notin S\}S={x∣x∈/​S}
我们既可以推导出 S⊆SS\subseteq SS⊆S, 又可以推导出 S⊈SS\nsubseteq SS⊈S.

  为避免悖论, 引入一个对整个推理体系稍有一点限制的小宇宙, 以使得在小宇宙内的讨论能避免悖论. 在可能引发悖论的地方, 默认使用小宇宙来加以限制.
  相关资料可参考Grothendieck宇宙.

1 范畴 (Category)

  与关心构造的集合论不同, 范畴论只关心对象的功能, 其对象具体是如何构造的, 不在范畴的讨论范围, 即所谓的抽象. 只要一个事物符合范畴的定义, 那都可以往范畴里套, 甚至包括从范畴出发引申出来的一些结构.
  符合下述要求的事物, 我们可以将其视作为一个范畴 C\mathcal{C}C:

  1. 有一群对象 Ob(C)\text{Ob}(\mathcal{C})Ob(C).
  2. 对象之间有一些箭头 Mor(C)\text{Mor}(\mathcal{C})Mor(C), 箭头的起点终点是确定的. 对象 AAA 到 BBB 的所有箭头记作 Hom(A,B)\text{Hom}(A, B)Hom(A,B).
  3. 如果有一个箭头 fff 是 A→BA→BA→B 的, 箭头 ggg 是 B→CB→CB→C 的, 那么总存在一个 A→CA→CA→C 的箭头, 他是 fff 和 ggg 的复合. 该复合的箭头可记作 g∘fg\circ fg∘f.
  4. 任意一个对象都有一个从自己出发并到达自己的恒等箭头. 对于某一对象 AAA 的恒等箭头, 记作 idA∈Hom(A,A)\text{id}_A\in\text{Hom}(A, A)idA​∈Hom(A,A). 满足对于任何从 AAA 出发的箭头 fff, 和到达 AAA 的箭头 ggg, 总有 f∘idA=ff\circ\text{id}_A=ff∘idA​=f, idA∘g=g\text{id}_A\circ g=gidA​∘g=g.

1.1 交换图

  以上定义涉及的一些定义与有向图比较相似, 所以有时会用称为交换图的有向图来表示范畴. 注意, 有向图中, 没画出来的箭头一般意味着不存在这个箭头, 而交换图中, 一般只画出部分当前讨论中有意义的箭头, 没画出来箭头不代表不存在. 下面是一个交换图描述范畴的例子. 其中恒等箭头 idA\text{id}_AidA​, idB\text{id}_BidB​ 等, 以及其他 Hom(A,B)\text{Hom}(A, B)Hom(A,B), Hom(A,C)\text{Hom}(A, C)Hom(A,C) 等箭头均被忽略.

#mermaid-svg-JjyPihkn4ym1Ny1H {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-JjyPihkn4ym1Ny1H .error-icon{fill:#552222;}#mermaid-svg-JjyPihkn4ym1Ny1H .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-JjyPihkn4ym1Ny1H .edge-thickness-normal{stroke-width:2px;}#mermaid-svg-JjyPihkn4ym1Ny1H .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-JjyPihkn4ym1Ny1H .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-JjyPihkn4ym1Ny1H .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-JjyPihkn4ym1Ny1H .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-JjyPihkn4ym1Ny1H .marker{fill:#333333;stroke:#333333;}#mermaid-svg-JjyPihkn4ym1Ny1H .marker.cross{stroke:#333333;}#mermaid-svg-JjyPihkn4ym1Ny1H svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-JjyPihkn4ym1Ny1H .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-JjyPihkn4ym1Ny1H .cluster-label text{fill:#333;}#mermaid-svg-JjyPihkn4ym1Ny1H .cluster-label span{color:#333;}#mermaid-svg-JjyPihkn4ym1Ny1H .label text,#mermaid-svg-JjyPihkn4ym1Ny1H span{fill:#333;color:#333;}#mermaid-svg-JjyPihkn4ym1Ny1H .node rect,#mermaid-svg-JjyPihkn4ym1Ny1H .node circle,#mermaid-svg-JjyPihkn4ym1Ny1H .node ellipse,#mermaid-svg-JjyPihkn4ym1Ny1H .node polygon,#mermaid-svg-JjyPihkn4ym1Ny1H .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-JjyPihkn4ym1Ny1H .node .label{text-align:center;}#mermaid-svg-JjyPihkn4ym1Ny1H .node.clickable{cursor:pointer;}#mermaid-svg-JjyPihkn4ym1Ny1H .arrowheadPath{fill:#333333;}#mermaid-svg-JjyPihkn4ym1Ny1H .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-JjyPihkn4ym1Ny1H .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-JjyPihkn4ym1Ny1H .edgeLabel{background-color:#e8e8e8;text-align:center;}#mermaid-svg-JjyPihkn4ym1Ny1H .edgeLabel rect{opacity:0.5;background-color:#e8e8e8;fill:#e8e8e8;}#mermaid-svg-JjyPihkn4ym1Ny1H .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-JjyPihkn4ym1Ny1H .cluster text{fill:#333;}#mermaid-svg-JjyPihkn4ym1Ny1H .cluster span{color:#333;}#mermaid-svg-JjyPihkn4ym1Ny1H div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-JjyPihkn4ym1Ny1H :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;}

f
g
h
X
Y
Z

  如果我们称一个有向图(例如上图和下图)是交换图,

#mermaid-svg-ZUeiNKhjvg7qtW0O {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-ZUeiNKhjvg7qtW0O .error-icon{fill:#552222;}#mermaid-svg-ZUeiNKhjvg7qtW0O .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-ZUeiNKhjvg7qtW0O .edge-thickness-normal{stroke-width:2px;}#mermaid-svg-ZUeiNKhjvg7qtW0O .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-ZUeiNKhjvg7qtW0O .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-ZUeiNKhjvg7qtW0O .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-ZUeiNKhjvg7qtW0O .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-ZUeiNKhjvg7qtW0O .marker{fill:#333333;stroke:#333333;}#mermaid-svg-ZUeiNKhjvg7qtW0O .marker.cross{stroke:#333333;}#mermaid-svg-ZUeiNKhjvg7qtW0O svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-ZUeiNKhjvg7qtW0O .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-ZUeiNKhjvg7qtW0O .cluster-label text{fill:#333;}#mermaid-svg-ZUeiNKhjvg7qtW0O .cluster-label span{color:#333;}#mermaid-svg-ZUeiNKhjvg7qtW0O .label text,#mermaid-svg-ZUeiNKhjvg7qtW0O span{fill:#333;color:#333;}#mermaid-svg-ZUeiNKhjvg7qtW0O .node rect,#mermaid-svg-ZUeiNKhjvg7qtW0O .node circle,#mermaid-svg-ZUeiNKhjvg7qtW0O .node ellipse,#mermaid-svg-ZUeiNKhjvg7qtW0O .node polygon,#mermaid-svg-ZUeiNKhjvg7qtW0O .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-ZUeiNKhjvg7qtW0O .node .label{text-align:center;}#mermaid-svg-ZUeiNKhjvg7qtW0O .node.clickable{cursor:pointer;}#mermaid-svg-ZUeiNKhjvg7qtW0O .arrowheadPath{fill:#333333;}#mermaid-svg-ZUeiNKhjvg7qtW0O .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-ZUeiNKhjvg7qtW0O .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-ZUeiNKhjvg7qtW0O .edgeLabel{background-color:#e8e8e8;text-align:center;}#mermaid-svg-ZUeiNKhjvg7qtW0O .edgeLabel rect{opacity:0.5;background-color:#e8e8e8;fill:#e8e8e8;}#mermaid-svg-ZUeiNKhjvg7qtW0O .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-ZUeiNKhjvg7qtW0O .cluster text{fill:#333;}#mermaid-svg-ZUeiNKhjvg7qtW0O .cluster span{color:#333;}#mermaid-svg-ZUeiNKhjvg7qtW0O div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-ZUeiNKhjvg7qtW0O :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;}

u
x
v
y
A
B
C
D

是指途中所有箭头的复合殊途同归, 即等式 h=g∘fh=g\circ fh=g∘f 和 y∘x=v∘uy\circ x=v\circ uy∘x=v∘u 恒成立.

1.2 示例

正整数与偏序关系

  正整数和大于等于关系可以构成一个范畴, 因为他满足如下范畴要求

  1. 对象 =Z+= \Z^+=Z+
  2. 箭头 ={a≥b∣a,b∈Z+}=\{a \ge b|a, b \in \Z^+\}={a≥b∣a,b∈Z+}
  3. 箭头的复合: 如果 a≥b∧b≥ca\ge b \land b \ge ca≥b∧b≥c, 那么有 a≥ca\ge ca≥c
  4. 恒等箭头: ida=a≥a\text{id}_a=a\ge aida​=a≥a

  其交换图大致如下

#mermaid-svg-9pRUnPAhVHFZBajG {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-9pRUnPAhVHFZBajG .error-icon{fill:#552222;}#mermaid-svg-9pRUnPAhVHFZBajG .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-9pRUnPAhVHFZBajG .edge-thickness-normal{stroke-width:2px;}#mermaid-svg-9pRUnPAhVHFZBajG .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-9pRUnPAhVHFZBajG .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-9pRUnPAhVHFZBajG .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-9pRUnPAhVHFZBajG .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-9pRUnPAhVHFZBajG .marker{fill:#333333;stroke:#333333;}#mermaid-svg-9pRUnPAhVHFZBajG .marker.cross{stroke:#333333;}#mermaid-svg-9pRUnPAhVHFZBajG svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-9pRUnPAhVHFZBajG .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-9pRUnPAhVHFZBajG .cluster-label text{fill:#333;}#mermaid-svg-9pRUnPAhVHFZBajG .cluster-label span{color:#333;}#mermaid-svg-9pRUnPAhVHFZBajG .label text,#mermaid-svg-9pRUnPAhVHFZBajG span{fill:#333;color:#333;}#mermaid-svg-9pRUnPAhVHFZBajG .node rect,#mermaid-svg-9pRUnPAhVHFZBajG .node circle,#mermaid-svg-9pRUnPAhVHFZBajG .node ellipse,#mermaid-svg-9pRUnPAhVHFZBajG .node polygon,#mermaid-svg-9pRUnPAhVHFZBajG .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-9pRUnPAhVHFZBajG .node .label{text-align:center;}#mermaid-svg-9pRUnPAhVHFZBajG .node.clickable{cursor:pointer;}#mermaid-svg-9pRUnPAhVHFZBajG .arrowheadPath{fill:#333333;}#mermaid-svg-9pRUnPAhVHFZBajG .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-9pRUnPAhVHFZBajG .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-9pRUnPAhVHFZBajG .edgeLabel{background-color:#e8e8e8;text-align:center;}#mermaid-svg-9pRUnPAhVHFZBajG .edgeLabel rect{opacity:0.5;background-color:#e8e8e8;fill:#e8e8e8;}#mermaid-svg-9pRUnPAhVHFZBajG .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-9pRUnPAhVHFZBajG .cluster text{fill:#333;}#mermaid-svg-9pRUnPAhVHFZBajG .cluster span{color:#333;}#mermaid-svg-9pRUnPAhVHFZBajG div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-9pRUnPAhVHFZBajG :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;}

1
2
3
4
...

  类似地, 正整数和小于等于关系同样可以构成一个范畴, 交换图大致如下

#mermaid-svg-NeA6991WyVZNpmVV {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-NeA6991WyVZNpmVV .error-icon{fill:#552222;}#mermaid-svg-NeA6991WyVZNpmVV .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-NeA6991WyVZNpmVV .edge-thickness-normal{stroke-width:2px;}#mermaid-svg-NeA6991WyVZNpmVV .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-NeA6991WyVZNpmVV .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-NeA6991WyVZNpmVV .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-NeA6991WyVZNpmVV .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-NeA6991WyVZNpmVV .marker{fill:#333333;stroke:#333333;}#mermaid-svg-NeA6991WyVZNpmVV .marker.cross{stroke:#333333;}#mermaid-svg-NeA6991WyVZNpmVV svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-NeA6991WyVZNpmVV .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-NeA6991WyVZNpmVV .cluster-label text{fill:#333;}#mermaid-svg-NeA6991WyVZNpmVV .cluster-label span{color:#333;}#mermaid-svg-NeA6991WyVZNpmVV .label text,#mermaid-svg-NeA6991WyVZNpmVV span{fill:#333;color:#333;}#mermaid-svg-NeA6991WyVZNpmVV .node rect,#mermaid-svg-NeA6991WyVZNpmVV .node circle,#mermaid-svg-NeA6991WyVZNpmVV .node ellipse,#mermaid-svg-NeA6991WyVZNpmVV .node polygon,#mermaid-svg-NeA6991WyVZNpmVV .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-NeA6991WyVZNpmVV .node .label{text-align:center;}#mermaid-svg-NeA6991WyVZNpmVV .node.clickable{cursor:pointer;}#mermaid-svg-NeA6991WyVZNpmVV .arrowheadPath{fill:#333333;}#mermaid-svg-NeA6991WyVZNpmVV .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-NeA6991WyVZNpmVV .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-NeA6991WyVZNpmVV .edgeLabel{background-color:#e8e8e8;text-align:center;}#mermaid-svg-NeA6991WyVZNpmVV .edgeLabel rect{opacity:0.5;background-color:#e8e8e8;fill:#e8e8e8;}#mermaid-svg-NeA6991WyVZNpmVV .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-NeA6991WyVZNpmVV .cluster text{fill:#333;}#mermaid-svg-NeA6991WyVZNpmVV .cluster span{color:#333;}#mermaid-svg-NeA6991WyVZNpmVV div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-NeA6991WyVZNpmVV :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;}

1
2
3
4
...

  整数和大于等于关系, 实数与大于等于关系等等, 都可以构成一个范畴.

矩阵范畴 (向量空间范畴的特例)

  矩阵, 或者简单点, 有限维矩阵可以构成一个范畴, 因为他满足如下范畴的要求

  1. 对象 ={1行矩阵,2行矩阵,3行矩阵,⋯}={n行矩阵∣n∈Z+}=\{1行矩阵, 2行矩阵,3行矩阵,\cdots\}=\{n行矩阵|n\in \Z^+\}={1行矩阵,2行矩阵,3行矩阵,⋯}={n行矩阵∣n∈Z+}
  2. 箭头 ={Mn×m∣n,m∈Z+}=\{M_{n\times m}|n,m\in \Z^+\}={Mn×m​∣n,m∈Z+}
  3. 箭头的复合: Mn×rMr×m=Mn×mM_{n\times r}M_{r\times m}=M_{n\times m}Mn×r​Mr×m​=Mn×m​, 即矩阵乘法
  4. 恒等箭头: idn行矩阵=In×n\text{id}_{n行矩阵}=I_{n\times n}idn行矩阵​=In×n​, 即单位矩阵

  其交换图大致如下:

#mermaid-svg-5eEUalFWbkMrdYzi {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-5eEUalFWbkMrdYzi .error-icon{fill:#552222;}#mermaid-svg-5eEUalFWbkMrdYzi .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-5eEUalFWbkMrdYzi .edge-thickness-normal{stroke-width:2px;}#mermaid-svg-5eEUalFWbkMrdYzi .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-5eEUalFWbkMrdYzi .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-5eEUalFWbkMrdYzi .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-5eEUalFWbkMrdYzi .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-5eEUalFWbkMrdYzi .marker{fill:#333333;stroke:#333333;}#mermaid-svg-5eEUalFWbkMrdYzi .marker.cross{stroke:#333333;}#mermaid-svg-5eEUalFWbkMrdYzi svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-5eEUalFWbkMrdYzi .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-5eEUalFWbkMrdYzi .cluster-label text{fill:#333;}#mermaid-svg-5eEUalFWbkMrdYzi .cluster-label span{color:#333;}#mermaid-svg-5eEUalFWbkMrdYzi .label text,#mermaid-svg-5eEUalFWbkMrdYzi span{fill:#333;color:#333;}#mermaid-svg-5eEUalFWbkMrdYzi .node rect,#mermaid-svg-5eEUalFWbkMrdYzi .node circle,#mermaid-svg-5eEUalFWbkMrdYzi .node ellipse,#mermaid-svg-5eEUalFWbkMrdYzi .node polygon,#mermaid-svg-5eEUalFWbkMrdYzi .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-5eEUalFWbkMrdYzi .node .label{text-align:center;}#mermaid-svg-5eEUalFWbkMrdYzi .node.clickable{cursor:pointer;}#mermaid-svg-5eEUalFWbkMrdYzi .arrowheadPath{fill:#333333;}#mermaid-svg-5eEUalFWbkMrdYzi .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-5eEUalFWbkMrdYzi .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-5eEUalFWbkMrdYzi .edgeLabel{background-color:#e8e8e8;text-align:center;}#mermaid-svg-5eEUalFWbkMrdYzi .edgeLabel rect{opacity:0.5;background-color:#e8e8e8;fill:#e8e8e8;}#mermaid-svg-5eEUalFWbkMrdYzi .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-5eEUalFWbkMrdYzi .cluster text{fill:#333;}#mermaid-svg-5eEUalFWbkMrdYzi .cluster span{color:#333;}#mermaid-svg-5eEUalFWbkMrdYzi div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-5eEUalFWbkMrdYzi :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;}

1
2
3
4
...

矩阵范畴在列举矩阵作为对象时, 抛弃了矩阵的列数, 以及其内容, 只保留了行数信息来进行抽象. 因此矩阵范畴和前述的正整数的范畴的交换图看上去有一点相似.

实数范畴1 (群范畴的特例)

  由于不假定读者有群论相关的知识, 因此这里只列举一个群的特例作为范畴的例子.
  实数也可以构成一个范畴, 满足的要求如下

  1. 对象 ={R}=\{R\}={R}, 只有单一一个对象, 这个对象是什么并无所谓.
  2. 箭头 =R=\R=R, 每个实数表示一个箭头, 每个箭头的起点和终点都是 RRR.
  3. 箭头的复合: 给定两个实数aaa, bbb, 总存在实数 c=a+bc=a+bc=a+b, 即实数加法
  4. 恒等箭头: 实数 000

  其交换图大致如下:

#mermaid-svg-4Jc428k2eNGZ6Png {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-4Jc428k2eNGZ6Png .error-icon{fill:#552222;}#mermaid-svg-4Jc428k2eNGZ6Png .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-4Jc428k2eNGZ6Png .edge-thickness-normal{stroke-width:2px;}#mermaid-svg-4Jc428k2eNGZ6Png .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-4Jc428k2eNGZ6Png .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-4Jc428k2eNGZ6Png .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-4Jc428k2eNGZ6Png .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-4Jc428k2eNGZ6Png .marker{fill:#333333;stroke:#333333;}#mermaid-svg-4Jc428k2eNGZ6Png .marker.cross{stroke:#333333;}#mermaid-svg-4Jc428k2eNGZ6Png svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-4Jc428k2eNGZ6Png .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-4Jc428k2eNGZ6Png .cluster-label text{fill:#333;}#mermaid-svg-4Jc428k2eNGZ6Png .cluster-label span{color:#333;}#mermaid-svg-4Jc428k2eNGZ6Png .label text,#mermaid-svg-4Jc428k2eNGZ6Png span{fill:#333;color:#333;}#mermaid-svg-4Jc428k2eNGZ6Png .node rect,#mermaid-svg-4Jc428k2eNGZ6Png .node circle,#mermaid-svg-4Jc428k2eNGZ6Png .node ellipse,#mermaid-svg-4Jc428k2eNGZ6Png .node polygon,#mermaid-svg-4Jc428k2eNGZ6Png .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-4Jc428k2eNGZ6Png .node .label{text-align:center;}#mermaid-svg-4Jc428k2eNGZ6Png .node.clickable{cursor:pointer;}#mermaid-svg-4Jc428k2eNGZ6Png .arrowheadPath{fill:#333333;}#mermaid-svg-4Jc428k2eNGZ6Png .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-4Jc428k2eNGZ6Png .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-4Jc428k2eNGZ6Png .edgeLabel{background-color:#e8e8e8;text-align:center;}#mermaid-svg-4Jc428k2eNGZ6Png .edgeLabel rect{opacity:0.5;background-color:#e8e8e8;fill:#e8e8e8;}#mermaid-svg-4Jc428k2eNGZ6Png .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-4Jc428k2eNGZ6Png .cluster text{fill:#333;}#mermaid-svg-4Jc428k2eNGZ6Png .cluster span{color:#333;}#mermaid-svg-4Jc428k2eNGZ6Png div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-4Jc428k2eNGZ6Png :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;}

0
1
2
3.14
...
R

实数范畴在列举对象时, 将所有实数信息都抛弃了, 直接用一个替代品 RRR 表示任一实数.

实数范畴2 (环范畴的特例)

  实数也可以构成一个范畴, 满足的要求如下

  1. 对象 ={R}=\{R\}={R}, 只有单一一个对象, 这个对象是什么并无所谓.
  2. 箭头 =R−{0}=\R-\{0\}=R−{0}, 每个实数表示一个箭头, 每个箭头的起点和终点都是 RRR.
  3. 箭头的复合: 给定两个实数aaa, bbb, 总存在实数 c=abc=abc=ab, 即实数乘法
  4. 恒等箭头: 实数 111

  其交换图大致如下:

#mermaid-svg-RgHi8P1jzj2Cv55D {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-RgHi8P1jzj2Cv55D .error-icon{fill:#552222;}#mermaid-svg-RgHi8P1jzj2Cv55D .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-RgHi8P1jzj2Cv55D .edge-thickness-normal{stroke-width:2px;}#mermaid-svg-RgHi8P1jzj2Cv55D .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-RgHi8P1jzj2Cv55D .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-RgHi8P1jzj2Cv55D .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-RgHi8P1jzj2Cv55D .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-RgHi8P1jzj2Cv55D .marker{fill:#333333;stroke:#333333;}#mermaid-svg-RgHi8P1jzj2Cv55D .marker.cross{stroke:#333333;}#mermaid-svg-RgHi8P1jzj2Cv55D svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-RgHi8P1jzj2Cv55D .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-RgHi8P1jzj2Cv55D .cluster-label text{fill:#333;}#mermaid-svg-RgHi8P1jzj2Cv55D .cluster-label span{color:#333;}#mermaid-svg-RgHi8P1jzj2Cv55D .label text,#mermaid-svg-RgHi8P1jzj2Cv55D span{fill:#333;color:#333;}#mermaid-svg-RgHi8P1jzj2Cv55D .node rect,#mermaid-svg-RgHi8P1jzj2Cv55D .node circle,#mermaid-svg-RgHi8P1jzj2Cv55D .node ellipse,#mermaid-svg-RgHi8P1jzj2Cv55D .node polygon,#mermaid-svg-RgHi8P1jzj2Cv55D .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-RgHi8P1jzj2Cv55D .node .label{text-align:center;}#mermaid-svg-RgHi8P1jzj2Cv55D .node.clickable{cursor:pointer;}#mermaid-svg-RgHi8P1jzj2Cv55D .arrowheadPath{fill:#333333;}#mermaid-svg-RgHi8P1jzj2Cv55D .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-RgHi8P1jzj2Cv55D .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-RgHi8P1jzj2Cv55D .edgeLabel{background-color:#e8e8e8;text-align:center;}#mermaid-svg-RgHi8P1jzj2Cv55D .edgeLabel rect{opacity:0.5;background-color:#e8e8e8;fill:#e8e8e8;}#mermaid-svg-RgHi8P1jzj2Cv55D .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-RgHi8P1jzj2Cv55D .cluster text{fill:#333;}#mermaid-svg-RgHi8P1jzj2Cv55D .cluster span{color:#333;}#mermaid-svg-RgHi8P1jzj2Cv55D div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-RgHi8P1jzj2Cv55D :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;}

1
2
1.5
3.14
...
R

集合范畴

  集合也可以构成一个范畴 Set\mathsf{Set}Set, 满足的要求如下

  1. 对象 =Set=\mathsf{Set}=Set, 所有的集合.
  2. 箭头 ={f:A→B∣A,B∈Set}=\{f: A \to B|A,B\in\mathsf{Set}\}={f:A→B∣A,B∈Set}, 所有集合间的映射
  3. 箭头的复合: 给定两个映射 f:A→Bf: A\to Bf:A→B, 和 g:B→Cg: B\to Cg:B→C, 总存在 g∘f:A→Cg\circ f:A\to Cg∘f:A→C
  4. 恒等箭头: 恒等映射 f:f:f: A→Ba↦a\begin{matrix}A\to B \\a\mapsto a\end{matrix}A→Ba↦a​

  其交换图随意列举如下:

#mermaid-svg-RCujeTigIOLf0Mbw {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-RCujeTigIOLf0Mbw .error-icon{fill:#552222;}#mermaid-svg-RCujeTigIOLf0Mbw .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-RCujeTigIOLf0Mbw .edge-thickness-normal{stroke-width:2px;}#mermaid-svg-RCujeTigIOLf0Mbw .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-RCujeTigIOLf0Mbw .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-RCujeTigIOLf0Mbw .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-RCujeTigIOLf0Mbw .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-RCujeTigIOLf0Mbw .marker{fill:#333333;stroke:#333333;}#mermaid-svg-RCujeTigIOLf0Mbw .marker.cross{stroke:#333333;}#mermaid-svg-RCujeTigIOLf0Mbw svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-RCujeTigIOLf0Mbw .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-RCujeTigIOLf0Mbw .cluster-label text{fill:#333;}#mermaid-svg-RCujeTigIOLf0Mbw .cluster-label span{color:#333;}#mermaid-svg-RCujeTigIOLf0Mbw .label text,#mermaid-svg-RCujeTigIOLf0Mbw span{fill:#333;color:#333;}#mermaid-svg-RCujeTigIOLf0Mbw .node rect,#mermaid-svg-RCujeTigIOLf0Mbw .node circle,#mermaid-svg-RCujeTigIOLf0Mbw .node ellipse,#mermaid-svg-RCujeTigIOLf0Mbw .node polygon,#mermaid-svg-RCujeTigIOLf0Mbw .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-RCujeTigIOLf0Mbw .node .label{text-align:center;}#mermaid-svg-RCujeTigIOLf0Mbw .node.clickable{cursor:pointer;}#mermaid-svg-RCujeTigIOLf0Mbw .arrowheadPath{fill:#333333;}#mermaid-svg-RCujeTigIOLf0Mbw .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-RCujeTigIOLf0Mbw .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-RCujeTigIOLf0Mbw .edgeLabel{background-color:#e8e8e8;text-align:center;}#mermaid-svg-RCujeTigIOLf0Mbw .edgeLabel rect{opacity:0.5;background-color:#e8e8e8;fill:#e8e8e8;}#mermaid-svg-RCujeTigIOLf0Mbw .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-RCujeTigIOLf0Mbw .cluster text{fill:#333;}#mermaid-svg-RCujeTigIOLf0Mbw .cluster span{color:#333;}#mermaid-svg-RCujeTigIOLf0Mbw div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-RCujeTigIOLf0Mbw :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;}

Q
C
I
R
...

  集合范畴在列举对象时, 将集合的内容抛弃了, 只要一个集合与其他集合的内容不同, 就可以单独视作一个对象.

数理逻辑范畴

  数理逻辑也可以构成一个范畴, 满足的要求如下:

  1. 对象 === 所有的命题.
  2. 箭头 === 对命题的推理.
  3. 箭头的复合: 两次对命题的推理合并成一次推理.
  4. 恒等箭头: 不推理, 保持原命题不变.

  其交换图随意列举如下:

#mermaid-svg-kbfNbI70Nmhwbzak {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-kbfNbI70Nmhwbzak .error-icon{fill:#552222;}#mermaid-svg-kbfNbI70Nmhwbzak .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-kbfNbI70Nmhwbzak .edge-thickness-normal{stroke-width:2px;}#mermaid-svg-kbfNbI70Nmhwbzak .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-kbfNbI70Nmhwbzak .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-kbfNbI70Nmhwbzak .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-kbfNbI70Nmhwbzak .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-kbfNbI70Nmhwbzak .marker{fill:#333333;stroke:#333333;}#mermaid-svg-kbfNbI70Nmhwbzak .marker.cross{stroke:#333333;}#mermaid-svg-kbfNbI70Nmhwbzak svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-kbfNbI70Nmhwbzak .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-kbfNbI70Nmhwbzak .cluster-label text{fill:#333;}#mermaid-svg-kbfNbI70Nmhwbzak .cluster-label span{color:#333;}#mermaid-svg-kbfNbI70Nmhwbzak .label text,#mermaid-svg-kbfNbI70Nmhwbzak span{fill:#333;color:#333;}#mermaid-svg-kbfNbI70Nmhwbzak .node rect,#mermaid-svg-kbfNbI70Nmhwbzak .node circle,#mermaid-svg-kbfNbI70Nmhwbzak .node ellipse,#mermaid-svg-kbfNbI70Nmhwbzak .node polygon,#mermaid-svg-kbfNbI70Nmhwbzak .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-kbfNbI70Nmhwbzak .node .label{text-align:center;}#mermaid-svg-kbfNbI70Nmhwbzak .node.clickable{cursor:pointer;}#mermaid-svg-kbfNbI70Nmhwbzak .arrowheadPath{fill:#333333;}#mermaid-svg-kbfNbI70Nmhwbzak .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-kbfNbI70Nmhwbzak .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-kbfNbI70Nmhwbzak .edgeLabel{background-color:#e8e8e8;text-align:center;}#mermaid-svg-kbfNbI70Nmhwbzak .edgeLabel rect{opacity:0.5;background-color:#e8e8e8;fill:#e8e8e8;}#mermaid-svg-kbfNbI70Nmhwbzak .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-kbfNbI70Nmhwbzak .cluster text{fill:#333;}#mermaid-svg-kbfNbI70Nmhwbzak .cluster span{color:#333;}#mermaid-svg-kbfNbI70Nmhwbzak div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-kbfNbI70Nmhwbzak :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;}

a=√b
b=a^2
b≥0
a≥0

Lua语言范畴 弱类型语言范畴

  Lua语言中所有对象都是由表和其他数据嵌套复合而成, Lua函数在定义时, 返回值数量是不确定的, 但在调用时是总是确定的. Lua的对象和(调用时的)函数可以构成一个范畴, 满足的要求如下

  1. 对象 ={0个对象的元组,1个对象的元组,2个对象的元组,⋯}=\{0个对象的元组, 1个对象的元组, 2个对象的元组, \cdots\}={0个对象的元组,1个对象的元组,2个对象的元组,⋯}.
  2. 箭头 ={n个形参m个返回值的无副作用的Lua函数∣n,m∈N}=\{n个形参m个返回值的无副作用的\text{Lua}函数| n,m\in \N\}={n个形参m个返回值的无副作用的Lua函数∣n,m∈N}.
  3. 箭头的复合: Lua函数的嵌套调用 g(f(...)).
  4. 恒等箭头: 如3个对象的元组的恒等箭头是 function (a, b, c) return a, b, c end.

  其交换图列举如下:

#mermaid-svg-O7vS5VFqUQJnXI1E {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-O7vS5VFqUQJnXI1E .error-icon{fill:#552222;}#mermaid-svg-O7vS5VFqUQJnXI1E .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-O7vS5VFqUQJnXI1E .edge-thickness-normal{stroke-width:2px;}#mermaid-svg-O7vS5VFqUQJnXI1E .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-O7vS5VFqUQJnXI1E .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-O7vS5VFqUQJnXI1E .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-O7vS5VFqUQJnXI1E .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-O7vS5VFqUQJnXI1E .marker{fill:#333333;stroke:#333333;}#mermaid-svg-O7vS5VFqUQJnXI1E .marker.cross{stroke:#333333;}#mermaid-svg-O7vS5VFqUQJnXI1E svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-O7vS5VFqUQJnXI1E .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-O7vS5VFqUQJnXI1E .cluster-label text{fill:#333;}#mermaid-svg-O7vS5VFqUQJnXI1E .cluster-label span{color:#333;}#mermaid-svg-O7vS5VFqUQJnXI1E .label text,#mermaid-svg-O7vS5VFqUQJnXI1E span{fill:#333;color:#333;}#mermaid-svg-O7vS5VFqUQJnXI1E .node rect,#mermaid-svg-O7vS5VFqUQJnXI1E .node circle,#mermaid-svg-O7vS5VFqUQJnXI1E .node ellipse,#mermaid-svg-O7vS5VFqUQJnXI1E .node polygon,#mermaid-svg-O7vS5VFqUQJnXI1E .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-O7vS5VFqUQJnXI1E .node .label{text-align:center;}#mermaid-svg-O7vS5VFqUQJnXI1E .node.clickable{cursor:pointer;}#mermaid-svg-O7vS5VFqUQJnXI1E .arrowheadPath{fill:#333333;}#mermaid-svg-O7vS5VFqUQJnXI1E .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-O7vS5VFqUQJnXI1E .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-O7vS5VFqUQJnXI1E .edgeLabel{background-color:#e8e8e8;text-align:center;}#mermaid-svg-O7vS5VFqUQJnXI1E .edgeLabel rect{opacity:0.5;background-color:#e8e8e8;fill:#e8e8e8;}#mermaid-svg-O7vS5VFqUQJnXI1E .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-O7vS5VFqUQJnXI1E .cluster text{fill:#333;}#mermaid-svg-O7vS5VFqUQJnXI1E .cluster span{color:#333;}#mermaid-svg-O7vS5VFqUQJnXI1E div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-O7vS5VFqUQJnXI1E :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;}

0
1
2
3
4
...

  Lua语言范畴在列举对象时, 将元组中对象的内容抛弃了. 而且由于缺少类型, 我们仅用自然数就一一列举出了所有的对象.

C语言范畴 强类型语言范畴

  C语言与Lua语言不同, 其具有了类型. 但由于C函数语法上只能返回一个返回值, 因此形式上, C语言无法构成范畴. 如果考虑将那些要求传入指针或是回调函数等来进行多值返回的函数视作多返回值函数, 那么C语言在此变换上才能构成一个范畴. 其他语言类同.

  假如func的第一个返回值通过语法上的返回值传回, 第二个返回值通过参数pc传回

D func(A a, B b, C* pc);

那么将其视作一个类如下的函数

func(A a, B b) -> C, D
  1. 对象 ={0个类型的元组,1个类型的元组,2个类型的元组,⋯}=\{0个类型的元组, 1个类型的元组, 2个类型的元组, \cdots\}={0个类型的元组,1个类型的元组,2个类型的元组,⋯}.
  2. 箭头 ={n个形参1个返回值的无副作用的C函数∣n∈N}=\{n个形参1个返回值的无副作用的\text{C}函数| n\in \N\}={n个形参1个返回值的无副作用的C函数∣n∈N}.
  3. 箭头的复合: C函数的嵌套调用 g(f(...)).
  4. 恒等箭头: 如1个类型的元组的恒等箭头是 A idA(A a) { return a; }.

  C标准库中的一部分函数的交换图列举如下:

#mermaid-svg-hhDx08sKzatKkEBn {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-hhDx08sKzatKkEBn .error-icon{fill:#552222;}#mermaid-svg-hhDx08sKzatKkEBn .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-hhDx08sKzatKkEBn .edge-thickness-normal{stroke-width:2px;}#mermaid-svg-hhDx08sKzatKkEBn .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-hhDx08sKzatKkEBn .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-hhDx08sKzatKkEBn .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-hhDx08sKzatKkEBn .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-hhDx08sKzatKkEBn .marker{fill:#333333;stroke:#333333;}#mermaid-svg-hhDx08sKzatKkEBn .marker.cross{stroke:#333333;}#mermaid-svg-hhDx08sKzatKkEBn svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-hhDx08sKzatKkEBn .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-hhDx08sKzatKkEBn .cluster-label text{fill:#333;}#mermaid-svg-hhDx08sKzatKkEBn .cluster-label span{color:#333;}#mermaid-svg-hhDx08sKzatKkEBn .label text,#mermaid-svg-hhDx08sKzatKkEBn span{fill:#333;color:#333;}#mermaid-svg-hhDx08sKzatKkEBn .node rect,#mermaid-svg-hhDx08sKzatKkEBn .node circle,#mermaid-svg-hhDx08sKzatKkEBn .node ellipse,#mermaid-svg-hhDx08sKzatKkEBn .node polygon,#mermaid-svg-hhDx08sKzatKkEBn .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-hhDx08sKzatKkEBn .node .label{text-align:center;}#mermaid-svg-hhDx08sKzatKkEBn .node.clickable{cursor:pointer;}#mermaid-svg-hhDx08sKzatKkEBn .arrowheadPath{fill:#333333;}#mermaid-svg-hhDx08sKzatKkEBn .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-hhDx08sKzatKkEBn .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-hhDx08sKzatKkEBn .edgeLabel{background-color:#e8e8e8;text-align:center;}#mermaid-svg-hhDx08sKzatKkEBn .edgeLabel rect{opacity:0.5;background-color:#e8e8e8;fill:#e8e8e8;}#mermaid-svg-hhDx08sKzatKkEBn .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-hhDx08sKzatKkEBn .cluster text{fill:#333;}#mermaid-svg-hhDx08sKzatKkEBn .cluster span{color:#333;}#mermaid-svg-hhDx08sKzatKkEBn div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-hhDx08sKzatKkEBn :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;}

fopen
fgetc
fread
strlen
fclose
fwrite
const char*, const char*
FILE*
int
size_t, size_t, FILE*
char*
size_t
FILE*, const void*, size_t, size_t

优雅语言范畴

  我们暂且不提有哪些语言符合我们要讨论的范畴, 我们只从范畴论的顶层理论的角度分析, 一个优雅的编程范式, 应当是什么样的.

  1. 应当能构成范畴, 即我们可以非常轻松地对各个功能进行组合
  2. 强类型的, 能对输入数据施加各种限制以避免外部的错误扩散到系统内部
  3. 简明的, 自注释的, 入参出参类型能很大程度地提示函数功能
  4. 解耦的, 职责和功能单一的

  下面列出一个优雅语言范畴的交换图:

#mermaid-svg-rY92GPzI8AMfa0XX {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-rY92GPzI8AMfa0XX .error-icon{fill:#552222;}#mermaid-svg-rY92GPzI8AMfa0XX .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-rY92GPzI8AMfa0XX .edge-thickness-normal{stroke-width:2px;}#mermaid-svg-rY92GPzI8AMfa0XX .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-rY92GPzI8AMfa0XX .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-rY92GPzI8AMfa0XX .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-rY92GPzI8AMfa0XX .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-rY92GPzI8AMfa0XX .marker{fill:#333333;stroke:#333333;}#mermaid-svg-rY92GPzI8AMfa0XX .marker.cross{stroke:#333333;}#mermaid-svg-rY92GPzI8AMfa0XX svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-rY92GPzI8AMfa0XX .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-rY92GPzI8AMfa0XX .cluster-label text{fill:#333;}#mermaid-svg-rY92GPzI8AMfa0XX .cluster-label span{color:#333;}#mermaid-svg-rY92GPzI8AMfa0XX .label text,#mermaid-svg-rY92GPzI8AMfa0XX span{fill:#333;color:#333;}#mermaid-svg-rY92GPzI8AMfa0XX .node rect,#mermaid-svg-rY92GPzI8AMfa0XX .node circle,#mermaid-svg-rY92GPzI8AMfa0XX .node ellipse,#mermaid-svg-rY92GPzI8AMfa0XX .node polygon,#mermaid-svg-rY92GPzI8AMfa0XX .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-rY92GPzI8AMfa0XX .node .label{text-align:center;}#mermaid-svg-rY92GPzI8AMfa0XX .node.clickable{cursor:pointer;}#mermaid-svg-rY92GPzI8AMfa0XX .arrowheadPath{fill:#333333;}#mermaid-svg-rY92GPzI8AMfa0XX .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-rY92GPzI8AMfa0XX .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-rY92GPzI8AMfa0XX .edgeLabel{background-color:#e8e8e8;text-align:center;}#mermaid-svg-rY92GPzI8AMfa0XX .edgeLabel rect{opacity:0.5;background-color:#e8e8e8;fill:#e8e8e8;}#mermaid-svg-rY92GPzI8AMfa0XX .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-rY92GPzI8AMfa0XX .cluster text{fill:#333;}#mermaid-svg-rY92GPzI8AMfa0XX .cluster span{color:#333;}#mermaid-svg-rY92GPzI8AMfa0XX div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-rY92GPzI8AMfa0XX :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;}

open
readAll
decode
exists
close
length
Json
业务
业务
业务
业务
Xml
业务
Url
业务
request
业务
length
Base64
decode
encode
FilePath
File
ByteArray
String
Boolean
Void
Int
Json
Date
Url
Xml
RequestInfo
Base64

  其中对象是类型的集合, 箭头是一些工具函数和业务函数.
  单看一张图, 我们就可以很轻松, 很快速地就能了解到这个系统能干哪些事情.
  前述弱类型语言和强类型语言, 在施加一定的约束后总能转换为优雅语言范畴.

  • 弱类型语言通过对值施加类型约束后, 可以得到强类型语言, 如JavaScript施加一定约束后, 可以得到TypeScript.
  • 强类型语言通过柯里化, 即多参函数化为单参函数, 可以化为函数式语言. 如C++的bind模板.
  • 函数式语言中, 对于有副作用的函数, 通过规范等措施限制副作用, 可以化为优雅语言.

  下面的举例中将以该优雅语言范畴为主要讨论对象.

2 函子 (Functor)

  设有两个范畴 C\mathcal{C}C, D\mathcal{D}D, 以及一对映射 FObF_\text{Ob}FOb​, FMorF_\text{Mor}FMor​, 满足

  1. 对象间的映射 FOb:Ob(D)→Ob(C)F_\text{Ob}: \text{Ob}(\mathcal{D}) \to\text{Ob}(\mathcal{C})FOb​:Ob(D)→Ob(C).
  2. 箭头间的映射 FMor:Mor(D)→Mor(C)F_\text{Mor}: \text{Mor}(\mathcal{D}) \to\text{Mor}(\mathcal{C})FMor​:Mor(D)→Mor(C).
  3. 对 D\mathcal{D}D 内, 从 AAA 到 BBB 间的任一箭头 f∈HomD(A,B)f\in \text{Hom}_{\mathcal{D}}(A, B)f∈HomD​(A,B), 都有 C\mathcal{C}C 内的一个 HomC(FObA,FObB)\text{Hom}_{\mathcal{C}}(F_\text{Ob}A, F_\text{Ob}B)HomC​(FOb​A,FOb​B) 内的一个箭头与 fff 对应.
  4. 对 D\mathcal{D}D 内, 任意两个箭头 fff, ggg, 等式 FMor(g∘f)=FMor(g)∘FMor(f)F_\text{Mor}(g\circ f)=F_\text{Mor}(g)\circ F_\text{Mor}(f)FMor​(g∘f)=FMor​(g)∘FMor​(f) 恒成立.
  5. 对 D\mathcal{D}D 内, 任意对象 XXX, 等式 FMor(idX)=idFMorXF_\text{Mor}(\text{id}_X)=\text{id}_{F_{\text{Mor}}X}FMor​(idX​)=idFMor​X​ 恒成立

  那么我们将这对映射 FObF_\text{Ob}FOb​, FMorF_\text{Mor}FMor​, 合并称作一个函子 FFF. 简而言之, 函子能将一个范畴 C\mathcal{C}C 映射成另一个范畴 D\mathcal{D}D, 记作 F:C→DF:\mathcal{C} \to \mathcal{D}F:C→D.

  对于两个范畴 C\mathcal{C}C, D\mathcal{D}D, 用 Fct (C,D)\text{Fct }(\mathcal{C}, \mathcal{D})Fct (C,D) 表示从 C\mathcal{C}C 到 D\mathcal{D}D 之间的所有函子.

  考虑有这样的一个编程语言的基础设施系统构成范畴 C\mathcal{C}C, 下面将频繁引用该范畴来举例.

#mermaid-svg-axeMmMnNb8i0cDJM {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-axeMmMnNb8i0cDJM .error-icon{fill:#552222;}#mermaid-svg-axeMmMnNb8i0cDJM .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-axeMmMnNb8i0cDJM .edge-thickness-normal{stroke-width:2px;}#mermaid-svg-axeMmMnNb8i0cDJM .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-axeMmMnNb8i0cDJM .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-axeMmMnNb8i0cDJM .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-axeMmMnNb8i0cDJM .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-axeMmMnNb8i0cDJM .marker{fill:#333333;stroke:#333333;}#mermaid-svg-axeMmMnNb8i0cDJM .marker.cross{stroke:#333333;}#mermaid-svg-axeMmMnNb8i0cDJM svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-axeMmMnNb8i0cDJM .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-axeMmMnNb8i0cDJM .cluster-label text{fill:#333;}#mermaid-svg-axeMmMnNb8i0cDJM .cluster-label span{color:#333;}#mermaid-svg-axeMmMnNb8i0cDJM .label text,#mermaid-svg-axeMmMnNb8i0cDJM span{fill:#333;color:#333;}#mermaid-svg-axeMmMnNb8i0cDJM .node rect,#mermaid-svg-axeMmMnNb8i0cDJM .node circle,#mermaid-svg-axeMmMnNb8i0cDJM .node ellipse,#mermaid-svg-axeMmMnNb8i0cDJM .node polygon,#mermaid-svg-axeMmMnNb8i0cDJM .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-axeMmMnNb8i0cDJM .node .label{text-align:center;}#mermaid-svg-axeMmMnNb8i0cDJM .node.clickable{cursor:pointer;}#mermaid-svg-axeMmMnNb8i0cDJM .arrowheadPath{fill:#333333;}#mermaid-svg-axeMmMnNb8i0cDJM .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-axeMmMnNb8i0cDJM .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-axeMmMnNb8i0cDJM .edgeLabel{background-color:#e8e8e8;text-align:center;}#mermaid-svg-axeMmMnNb8i0cDJM .edgeLabel rect{opacity:0.5;background-color:#e8e8e8;fill:#e8e8e8;}#mermaid-svg-axeMmMnNb8i0cDJM .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-axeMmMnNb8i0cDJM .cluster text{fill:#333;}#mermaid-svg-axeMmMnNb8i0cDJM .cluster span{color:#333;}#mermaid-svg-axeMmMnNb8i0cDJM div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-axeMmMnNb8i0cDJM :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;}

open
readAll
decode
exists
FilePath
File
ByteArray
String
Boolean

2.1 拟等函子

  如果函子将对象映射回自己, 将箭头也映射回自己, 那么称该函子为拟等函子.

钩子函子

  钩子函子不是唯一的, 需要由业务方提供一个自定义的处理函数后才能特化出一个钩子.

  • 形式上, 钩子函子映射回原范畴. 即 Hook C=C\text{Hook }\mathcal{C}=\mathcal{C}Hook C=C.
  • 功能上, 钩子函子监视每个函数的输入值输出值, 将其传给自定义的处理函数, 实现所谓"钩"起值的能力.

  下面是一些常见的钩子函子:

  • 日志记录
  • 值过滤
  • 程序流拦截
  • 执行耗时记录
  • 自动析构

2.2 忘却函子

  C语言的程序在编译后即丢失类型信息, 但各函数的入参出参的调用协议依然存在于汇编码之中, 即原来的类型元组的对象的信息在编译后只剩下参数数量信息. 编译后生成的汇编代码在汇编接口层面仍然构成一个C汇编范畴, 这个范畴类似于Lua范畴. 并且由于C语言范畴到C汇编范畴之间存在一个映射关系, 我们有一个函子可以描述这两个范畴的关系: 忘却函子.
  类似地, Java语言中, 我们可以进行泛型编程. 编译后, Java的泛型类型将进行类型擦除, 丢弃掉其泛型参数中的类型信息. 但由于原泛型类型到类型擦除后的泛型类型之间也有一个映射关系, 这个映射关系也描述了一个忘却函子.

2.3 可逆函子

空化函子 (Nullable) 非空化函子 (NonNullable)

  范畴 C\mathcal{C}C 中每个函数都有可能出错, 比如从FilePath到File的函数就有可能失败, 或是因为文件不存在, 或是因为文件路径指向的是一个文件夹. 如果某个函数失败会导致异常抛出, 那么基于这个系统建设出来的业务就很容易出错.
  空化函子可以将上述范畴, 映射成这样的范畴 Nullable C\text{Nullable }\mathcal{C}Nullable C

#mermaid-svg-J6QYk5N8S0Scw9PK {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-J6QYk5N8S0Scw9PK .error-icon{fill:#552222;}#mermaid-svg-J6QYk5N8S0Scw9PK .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-J6QYk5N8S0Scw9PK .edge-thickness-normal{stroke-width:2px;}#mermaid-svg-J6QYk5N8S0Scw9PK .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-J6QYk5N8S0Scw9PK .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-J6QYk5N8S0Scw9PK .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-J6QYk5N8S0Scw9PK .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-J6QYk5N8S0Scw9PK .marker{fill:#333333;stroke:#333333;}#mermaid-svg-J6QYk5N8S0Scw9PK .marker.cross{stroke:#333333;}#mermaid-svg-J6QYk5N8S0Scw9PK svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-J6QYk5N8S0Scw9PK .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-J6QYk5N8S0Scw9PK .cluster-label text{fill:#333;}#mermaid-svg-J6QYk5N8S0Scw9PK .cluster-label span{color:#333;}#mermaid-svg-J6QYk5N8S0Scw9PK .label text,#mermaid-svg-J6QYk5N8S0Scw9PK span{fill:#333;color:#333;}#mermaid-svg-J6QYk5N8S0Scw9PK .node rect,#mermaid-svg-J6QYk5N8S0Scw9PK .node circle,#mermaid-svg-J6QYk5N8S0Scw9PK .node ellipse,#mermaid-svg-J6QYk5N8S0Scw9PK .node polygon,#mermaid-svg-J6QYk5N8S0Scw9PK .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-J6QYk5N8S0Scw9PK .node .label{text-align:center;}#mermaid-svg-J6QYk5N8S0Scw9PK .node.clickable{cursor:pointer;}#mermaid-svg-J6QYk5N8S0Scw9PK .arrowheadPath{fill:#333333;}#mermaid-svg-J6QYk5N8S0Scw9PK .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-J6QYk5N8S0Scw9PK .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-J6QYk5N8S0Scw9PK .edgeLabel{background-color:#e8e8e8;text-align:center;}#mermaid-svg-J6QYk5N8S0Scw9PK .edgeLabel rect{opacity:0.5;background-color:#e8e8e8;fill:#e8e8e8;}#mermaid-svg-J6QYk5N8S0Scw9PK .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-J6QYk5N8S0Scw9PK .cluster text{fill:#333;}#mermaid-svg-J6QYk5N8S0Scw9PK .cluster span{color:#333;}#mermaid-svg-J6QYk5N8S0Scw9PK div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-J6QYk5N8S0Scw9PK :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;}

open
readAll
decode
exists
FilePath?
File?
ByteArray?
String?
Boolean?

  其中空化函子包装每一个类型为可空类型, 包装每一个函数, 或是用try catch语句包住, 或是其他操作, 确保他们不会是抛出异常, 而是返回一个空值取而代之.
  现代编程语言中, 很多都提供了一个类似于Option的泛型类, 能帮助我们进行空化函子的变换.

  非空化函子与空化函子构成一对逆函子.
  非空化函子可以将范畴 Nullable(C)\text{Nullable}(\mathcal{C})Nullable(C) 映射回 C=NonNullable Nullable C\mathcal{C}=\text{NonNullable }\text{Nullable }\mathcal{C}C=NonNullable Nullable C

捕获函子 (Catching) 抛出函子 (Throwing)

  捕获函子, 可以将范畴 C\mathcal{C}C, 映射成如下范畴 Catching C\text{Catching }\mathcal{C}Catching C

#mermaid-svg-2WRjKt3t8YgkvHUo {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-2WRjKt3t8YgkvHUo .error-icon{fill:#552222;}#mermaid-svg-2WRjKt3t8YgkvHUo .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-2WRjKt3t8YgkvHUo .edge-thickness-normal{stroke-width:2px;}#mermaid-svg-2WRjKt3t8YgkvHUo .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-2WRjKt3t8YgkvHUo .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-2WRjKt3t8YgkvHUo .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-2WRjKt3t8YgkvHUo .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-2WRjKt3t8YgkvHUo .marker{fill:#333333;stroke:#333333;}#mermaid-svg-2WRjKt3t8YgkvHUo .marker.cross{stroke:#333333;}#mermaid-svg-2WRjKt3t8YgkvHUo svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-2WRjKt3t8YgkvHUo .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-2WRjKt3t8YgkvHUo .cluster-label text{fill:#333;}#mermaid-svg-2WRjKt3t8YgkvHUo .cluster-label span{color:#333;}#mermaid-svg-2WRjKt3t8YgkvHUo .label text,#mermaid-svg-2WRjKt3t8YgkvHUo span{fill:#333;color:#333;}#mermaid-svg-2WRjKt3t8YgkvHUo .node rect,#mermaid-svg-2WRjKt3t8YgkvHUo .node circle,#mermaid-svg-2WRjKt3t8YgkvHUo .node ellipse,#mermaid-svg-2WRjKt3t8YgkvHUo .node polygon,#mermaid-svg-2WRjKt3t8YgkvHUo .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-2WRjKt3t8YgkvHUo .node .label{text-align:center;}#mermaid-svg-2WRjKt3t8YgkvHUo .node.clickable{cursor:pointer;}#mermaid-svg-2WRjKt3t8YgkvHUo .arrowheadPath{fill:#333333;}#mermaid-svg-2WRjKt3t8YgkvHUo .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-2WRjKt3t8YgkvHUo .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-2WRjKt3t8YgkvHUo .edgeLabel{background-color:#e8e8e8;text-align:center;}#mermaid-svg-2WRjKt3t8YgkvHUo .edgeLabel rect{opacity:0.5;background-color:#e8e8e8;fill:#e8e8e8;}#mermaid-svg-2WRjKt3t8YgkvHUo .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-2WRjKt3t8YgkvHUo .cluster text{fill:#333;}#mermaid-svg-2WRjKt3t8YgkvHUo .cluster span{color:#333;}#mermaid-svg-2WRjKt3t8YgkvHUo div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-2WRjKt3t8YgkvHUo :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;}

open
readAll
decode
exists
Result[FilePath]
Result[File]
Result[ByteArray]
Result[String]
Result[Boolean]

  Result[T]有两个可能取值, 一是T类型的值, 二是异常.

  捕获函子与抛出函子构成一对逆函子.
  捕获函子可以将范畴 Catching C\text{Catching }\mathcal{C}Catching C 映射回 C=Throwing Catching C\mathcal{C}=\text{Throwing }\text{Catching }\mathcal{C}C=Throwing Catching C

惰化函子 (Lazy)

  惰化函子, 可以将范畴 C\mathcal{C}C, 映射成如下范畴 Lazy C\text{Lazy }\mathcal{C}Lazy C

#mermaid-svg-8KgNiAw6aj8pZJIx {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-8KgNiAw6aj8pZJIx .error-icon{fill:#552222;}#mermaid-svg-8KgNiAw6aj8pZJIx .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-8KgNiAw6aj8pZJIx .edge-thickness-normal{stroke-width:2px;}#mermaid-svg-8KgNiAw6aj8pZJIx .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-8KgNiAw6aj8pZJIx .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-8KgNiAw6aj8pZJIx .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-8KgNiAw6aj8pZJIx .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-8KgNiAw6aj8pZJIx .marker{fill:#333333;stroke:#333333;}#mermaid-svg-8KgNiAw6aj8pZJIx .marker.cross{stroke:#333333;}#mermaid-svg-8KgNiAw6aj8pZJIx svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-8KgNiAw6aj8pZJIx .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-8KgNiAw6aj8pZJIx .cluster-label text{fill:#333;}#mermaid-svg-8KgNiAw6aj8pZJIx .cluster-label span{color:#333;}#mermaid-svg-8KgNiAw6aj8pZJIx .label text,#mermaid-svg-8KgNiAw6aj8pZJIx span{fill:#333;color:#333;}#mermaid-svg-8KgNiAw6aj8pZJIx .node rect,#mermaid-svg-8KgNiAw6aj8pZJIx .node circle,#mermaid-svg-8KgNiAw6aj8pZJIx .node ellipse,#mermaid-svg-8KgNiAw6aj8pZJIx .node polygon,#mermaid-svg-8KgNiAw6aj8pZJIx .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-8KgNiAw6aj8pZJIx .node .label{text-align:center;}#mermaid-svg-8KgNiAw6aj8pZJIx .node.clickable{cursor:pointer;}#mermaid-svg-8KgNiAw6aj8pZJIx .arrowheadPath{fill:#333333;}#mermaid-svg-8KgNiAw6aj8pZJIx .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-8KgNiAw6aj8pZJIx .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-8KgNiAw6aj8pZJIx .edgeLabel{background-color:#e8e8e8;text-align:center;}#mermaid-svg-8KgNiAw6aj8pZJIx .edgeLabel rect{opacity:0.5;background-color:#e8e8e8;fill:#e8e8e8;}#mermaid-svg-8KgNiAw6aj8pZJIx .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-8KgNiAw6aj8pZJIx .cluster text{fill:#333;}#mermaid-svg-8KgNiAw6aj8pZJIx .cluster span{color:#333;}#mermaid-svg-8KgNiAw6aj8pZJIx div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-8KgNiAw6aj8pZJIx :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;}

open
readAll
decode
exists
Lazy[FilePath]
Lazy[File]
Lazy[ByteArray]
Lazy[String]
Lazy[Boolean]

  其中Lazy泛型接口可以定义如下:

interface Lazy<T> {val value: T
}

  函子中对函数的包装器可以定义如下:

fun<T, U> Lazy<T>.map(action: (T) -> U) -> Lazy<U> = object : Lazy<U> {override val value: U by lazy {action(this@map.value)}
}

  只有当业务方主动调用value时, 在惰性对象上附加的一系列操作才会开始被执行.
  相应地, 可以定义积极函子. 惰化函子与积极函子构成一对逆函子.

异步函子 (Async) 同步函子 (Sync)

  异步函子, 可以将范畴 C\mathcal{C}C, 映射成如下范畴 Async C\text{Async }\mathcal{C}Async C

#mermaid-svg-HWEF8JWgFc04R8lh {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-HWEF8JWgFc04R8lh .error-icon{fill:#552222;}#mermaid-svg-HWEF8JWgFc04R8lh .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-HWEF8JWgFc04R8lh .edge-thickness-normal{stroke-width:2px;}#mermaid-svg-HWEF8JWgFc04R8lh .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-HWEF8JWgFc04R8lh .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-HWEF8JWgFc04R8lh .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-HWEF8JWgFc04R8lh .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-HWEF8JWgFc04R8lh .marker{fill:#333333;stroke:#333333;}#mermaid-svg-HWEF8JWgFc04R8lh .marker.cross{stroke:#333333;}#mermaid-svg-HWEF8JWgFc04R8lh svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-HWEF8JWgFc04R8lh .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-HWEF8JWgFc04R8lh .cluster-label text{fill:#333;}#mermaid-svg-HWEF8JWgFc04R8lh .cluster-label span{color:#333;}#mermaid-svg-HWEF8JWgFc04R8lh .label text,#mermaid-svg-HWEF8JWgFc04R8lh span{fill:#333;color:#333;}#mermaid-svg-HWEF8JWgFc04R8lh .node rect,#mermaid-svg-HWEF8JWgFc04R8lh .node circle,#mermaid-svg-HWEF8JWgFc04R8lh .node ellipse,#mermaid-svg-HWEF8JWgFc04R8lh .node polygon,#mermaid-svg-HWEF8JWgFc04R8lh .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-HWEF8JWgFc04R8lh .node .label{text-align:center;}#mermaid-svg-HWEF8JWgFc04R8lh .node.clickable{cursor:pointer;}#mermaid-svg-HWEF8JWgFc04R8lh .arrowheadPath{fill:#333333;}#mermaid-svg-HWEF8JWgFc04R8lh .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-HWEF8JWgFc04R8lh .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-HWEF8JWgFc04R8lh .edgeLabel{background-color:#e8e8e8;text-align:center;}#mermaid-svg-HWEF8JWgFc04R8lh .edgeLabel rect{opacity:0.5;background-color:#e8e8e8;fill:#e8e8e8;}#mermaid-svg-HWEF8JWgFc04R8lh .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-HWEF8JWgFc04R8lh .cluster text{fill:#333;}#mermaid-svg-HWEF8JWgFc04R8lh .cluster span{color:#333;}#mermaid-svg-HWEF8JWgFc04R8lh div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-HWEF8JWgFc04R8lh :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;}

open
readAll
decode
exists
Future[FilePath]
Future[File]
Future[ByteArray]
Future[String]
Future[Boolean]

  其中Future泛型接口可以实现如下:

interface Future<T> {val value: T
}

  函子中对函数的包装器可以实现如下:

fun<T, U> Future<T>.does(action: (T) -> U) -> Future<U> = object : Future<U> {override val value: U get() = action(this@map.value)
}

  同步函子与异步函子构成一对逆函子.
  同步函子可以将范畴 Async C\text{Async }\mathcal{C}Async C 映射回 C=Sync Async C\mathcal{C}=\text{Sync }\text{Async }\mathcal{C}C=Sync Async C

2.4 拟逆函子

迭代函子 (ForEach)

  迭代函子, 可以将范畴 C\mathcal{C}C, 映射成如下范畴 ForEach C\text{ForEach }\mathcal{C}ForEach C

#mermaid-svg-FN5mhJSO27qLxsEy {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-FN5mhJSO27qLxsEy .error-icon{fill:#552222;}#mermaid-svg-FN5mhJSO27qLxsEy .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-FN5mhJSO27qLxsEy .edge-thickness-normal{stroke-width:2px;}#mermaid-svg-FN5mhJSO27qLxsEy .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-FN5mhJSO27qLxsEy .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-FN5mhJSO27qLxsEy .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-FN5mhJSO27qLxsEy .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-FN5mhJSO27qLxsEy .marker{fill:#333333;stroke:#333333;}#mermaid-svg-FN5mhJSO27qLxsEy .marker.cross{stroke:#333333;}#mermaid-svg-FN5mhJSO27qLxsEy svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-FN5mhJSO27qLxsEy .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-FN5mhJSO27qLxsEy .cluster-label text{fill:#333;}#mermaid-svg-FN5mhJSO27qLxsEy .cluster-label span{color:#333;}#mermaid-svg-FN5mhJSO27qLxsEy .label text,#mermaid-svg-FN5mhJSO27qLxsEy span{fill:#333;color:#333;}#mermaid-svg-FN5mhJSO27qLxsEy .node rect,#mermaid-svg-FN5mhJSO27qLxsEy .node circle,#mermaid-svg-FN5mhJSO27qLxsEy .node ellipse,#mermaid-svg-FN5mhJSO27qLxsEy .node polygon,#mermaid-svg-FN5mhJSO27qLxsEy .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-FN5mhJSO27qLxsEy .node .label{text-align:center;}#mermaid-svg-FN5mhJSO27qLxsEy .node.clickable{cursor:pointer;}#mermaid-svg-FN5mhJSO27qLxsEy .arrowheadPath{fill:#333333;}#mermaid-svg-FN5mhJSO27qLxsEy .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-FN5mhJSO27qLxsEy .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-FN5mhJSO27qLxsEy .edgeLabel{background-color:#e8e8e8;text-align:center;}#mermaid-svg-FN5mhJSO27qLxsEy .edgeLabel rect{opacity:0.5;background-color:#e8e8e8;fill:#e8e8e8;}#mermaid-svg-FN5mhJSO27qLxsEy .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-FN5mhJSO27qLxsEy .cluster text{fill:#333;}#mermaid-svg-FN5mhJSO27qLxsEy .cluster span{color:#333;}#mermaid-svg-FN5mhJSO27qLxsEy div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-FN5mhJSO27qLxsEy :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;}

open
readAll
decode
exists
Iterable[FilePath]
Iterable[File]
Iterable[ByteArray]
Iterable[String]
Iterable[Boolean]

  经过迭代函子映射后, 其中的函数均拥有了对一组对象进行操作的能力.

迭代函子的拟逆函子

  迭代函子的拟逆函子很多, 如

  • 取首位 (First)
  • 取末位 (Last)
  • 任一值 (Single)
  • 索引 (Index), 需要一个索引值 i∈Ni\in \Ni∈N
  • 查找 (FindFirst), 需要一个筛选映射 f:Ob(C)→Boolf: \text{Ob}(\mathcal{C})\to \text{Bool}f:Ob(C)→Bool
  • 规约 (Reduce), 需要一个满足结合律的(即半群)规约映射来构造, 下列均同.
  • 最大值 (Max)
  • 最小值 (Min)
  • 平均值 (Average)

  取首位函子, 取末位函子等可以将迭代的类型包装去除, 映射回原范畴. 即 First ForEach C=Last ForEach C=C\text{First }\text{ForEach }\mathcal{C}=\text{Last }\text{ForEach }\mathcal{C}=\mathcal{C}First ForEach C=Last ForEach C=C. 取首位函子和取末位函子等都是迭代函子的拟逆函子.

迭代范畴的自函子

  对于任意迭代函子映射下的范畴 D=ForEach C\mathcal{D}=\text{ForEach }\mathcal{C}D=ForEach C, 我们称之为迭代子范畴, 简称迭代范畴. 下列是迭代范畴中的一些自函子.

  • 打乱 (Shuffle)
  • 排序 (Sort)
  • 过滤 (Filter), 需要一个筛选映射 f:Ob(C)→Boolf: \text{Ob}(\mathcal{C})\to \text{Bool}f:Ob(C)→Bool
  • 局部 (Take, Drop, Window)
  • 半分 (Partition)
  • 去重 (Ticker)
  • 积分 (Fold), 需要一个满足结合律的(即半群)规约映射来构造.

  其中有 FindFirstfD=First FilterfD\text{FindFirst}_{f}\mathcal{D}=\text{First }\text{Filter}_{f}\mathcal{D}FindFirstf​D=First Filterf​D.

2.5 映射函子 (Map)

  映射函子是自定义函子的基本工具之一, 上述大部分函子都可以用映射函子配合一个具体函数来实现. 映射函子可以将范畴 C\mathcal{C}C 映射成如下范畴 Map C\text{Map }\mathcal{C}Map C. 其中 A,B,⋯A, B, \cdotsA,B,⋯ 均是某些具体类型.

#mermaid-svg-kp0akzRbcLdYCkaE {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-kp0akzRbcLdYCkaE .error-icon{fill:#552222;}#mermaid-svg-kp0akzRbcLdYCkaE .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-kp0akzRbcLdYCkaE .edge-thickness-normal{stroke-width:2px;}#mermaid-svg-kp0akzRbcLdYCkaE .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-kp0akzRbcLdYCkaE .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-kp0akzRbcLdYCkaE .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-kp0akzRbcLdYCkaE .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-kp0akzRbcLdYCkaE .marker{fill:#333333;stroke:#333333;}#mermaid-svg-kp0akzRbcLdYCkaE .marker.cross{stroke:#333333;}#mermaid-svg-kp0akzRbcLdYCkaE svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-kp0akzRbcLdYCkaE .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-kp0akzRbcLdYCkaE .cluster-label text{fill:#333;}#mermaid-svg-kp0akzRbcLdYCkaE .cluster-label span{color:#333;}#mermaid-svg-kp0akzRbcLdYCkaE .label text,#mermaid-svg-kp0akzRbcLdYCkaE span{fill:#333;color:#333;}#mermaid-svg-kp0akzRbcLdYCkaE .node rect,#mermaid-svg-kp0akzRbcLdYCkaE .node circle,#mermaid-svg-kp0akzRbcLdYCkaE .node ellipse,#mermaid-svg-kp0akzRbcLdYCkaE .node polygon,#mermaid-svg-kp0akzRbcLdYCkaE .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-kp0akzRbcLdYCkaE .node .label{text-align:center;}#mermaid-svg-kp0akzRbcLdYCkaE .node.clickable{cursor:pointer;}#mermaid-svg-kp0akzRbcLdYCkaE .arrowheadPath{fill:#333333;}#mermaid-svg-kp0akzRbcLdYCkaE .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-kp0akzRbcLdYCkaE .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-kp0akzRbcLdYCkaE .edgeLabel{background-color:#e8e8e8;text-align:center;}#mermaid-svg-kp0akzRbcLdYCkaE .edgeLabel rect{opacity:0.5;background-color:#e8e8e8;fill:#e8e8e8;}#mermaid-svg-kp0akzRbcLdYCkaE .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-kp0akzRbcLdYCkaE .cluster text{fill:#333;}#mermaid-svg-kp0akzRbcLdYCkaE .cluster span{color:#333;}#mermaid-svg-kp0akzRbcLdYCkaE div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-kp0akzRbcLdYCkaE :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;}

open
readAll
decode
exists
A
B
C
D
E

  特别地, 如果上述具体类型都是同一个类型, 其交换图类如下

#mermaid-svg-x0u41MOik1lMGBA1 {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-x0u41MOik1lMGBA1 .error-icon{fill:#552222;}#mermaid-svg-x0u41MOik1lMGBA1 .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-x0u41MOik1lMGBA1 .edge-thickness-normal{stroke-width:2px;}#mermaid-svg-x0u41MOik1lMGBA1 .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-x0u41MOik1lMGBA1 .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-x0u41MOik1lMGBA1 .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-x0u41MOik1lMGBA1 .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-x0u41MOik1lMGBA1 .marker{fill:#333333;stroke:#333333;}#mermaid-svg-x0u41MOik1lMGBA1 .marker.cross{stroke:#333333;}#mermaid-svg-x0u41MOik1lMGBA1 svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-x0u41MOik1lMGBA1 .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-x0u41MOik1lMGBA1 .cluster-label text{fill:#333;}#mermaid-svg-x0u41MOik1lMGBA1 .cluster-label span{color:#333;}#mermaid-svg-x0u41MOik1lMGBA1 .label text,#mermaid-svg-x0u41MOik1lMGBA1 span{fill:#333;color:#333;}#mermaid-svg-x0u41MOik1lMGBA1 .node rect,#mermaid-svg-x0u41MOik1lMGBA1 .node circle,#mermaid-svg-x0u41MOik1lMGBA1 .node ellipse,#mermaid-svg-x0u41MOik1lMGBA1 .node polygon,#mermaid-svg-x0u41MOik1lMGBA1 .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-x0u41MOik1lMGBA1 .node .label{text-align:center;}#mermaid-svg-x0u41MOik1lMGBA1 .node.clickable{cursor:pointer;}#mermaid-svg-x0u41MOik1lMGBA1 .arrowheadPath{fill:#333333;}#mermaid-svg-x0u41MOik1lMGBA1 .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-x0u41MOik1lMGBA1 .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-x0u41MOik1lMGBA1 .edgeLabel{background-color:#e8e8e8;text-align:center;}#mermaid-svg-x0u41MOik1lMGBA1 .edgeLabel rect{opacity:0.5;background-color:#e8e8e8;fill:#e8e8e8;}#mermaid-svg-x0u41MOik1lMGBA1 .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-x0u41MOik1lMGBA1 .cluster text{fill:#333;}#mermaid-svg-x0u41MOik1lMGBA1 .cluster span{color:#333;}#mermaid-svg-x0u41MOik1lMGBA1 div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-x0u41MOik1lMGBA1 :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;}

open
readAll
decode
exists
A

如此操作的得到的映射函子是一个忘却函子, 能将其对象的类型信息忘却.

2.6 自函子 (Endofunctor) 单子 (monad)

  如果一个函子是从一个范畴 C\mathcal{C}C 出发, 映射回自己的范畴 C\mathcal{C}C, 那么我们称该函子为自函子. 对于任意范畴, 其所有的自函子可以表示成 Fct(C,C)\text{Fct}(\mathcal{C}, \mathcal{C})Fct(C,C).
  上述示例中提到的大部分函子事实上都只是将一个类型转为另一个类型, 将一个函数转为另一个函数, 并未超出这些程序语言可表达的范围之外, 本质上这些函子都只是将一个语言范畴映射回到自己之内, 即 F:C→CF: \mathcal{C} \to \mathcal{C}F:C→C, Fct(C,C)={F∣F:C→C}\text{Fct}(\mathcal{C}, \mathcal{C})=\{F|F:\mathcal{C}\to\mathcal{C}\}Fct(C,C)={F∣F:C→C}
  对于所有的这样的 C→C\mathcal{C} \to \mathcal{C}C→C 的函子所构成的集合 Fct(C,C)\text{Fct}(\mathcal{C}, \mathcal{C})Fct(C,C)(以及函子之间的复合运算), 我们称之为单子.
  单子天然构成一个幺半群, 即单子天然满足

  • 封闭性: 对于任意范畴 C\mathcal{C}C, 其上的任意两个函子 F,G∈Fct(C,C)F, G\in \text{Fct}(\mathcal{C}, \mathcal{C})F,G∈Fct(C,C), 其复合仍在集合内 G∘F∈Fct(C,C)G\circ F\in\text{Fct}(\mathcal{C}, \mathcal{C})G∘F∈Fct(C,C)
  • 结合律: 对于任意范畴 C\mathcal{C}C, 其上的任意三个函子 F,G,H∈Fct(C,C)F, G, H\in \text{Fct}(\mathcal{C}, \mathcal{C})F,G,H∈Fct(C,C), 等式 (H∘G)∘F=H∘(G∘F)(H\circ G)\circ F=H\circ (G\circ F)(H∘G)∘F=H∘(G∘F) 恒成立.
  • 幺元: 对于任意范畴 C\mathcal{C}C, 总相应且唯一地有一个恒等函子 idC∈Fct(C,C)\text{id}_\mathcal{C}\in\text{Fct}(\mathcal{C}, \mathcal{C})idC​∈Fct(C,C), 对于任意函子 F∈Fct(C,C)F\in\text{Fct}(\mathcal{C}, \mathcal{C})F∈Fct(C,C), 等式 idC∘F=F∘idC=F\text{id}_\mathcal{C}\circ F=F\circ\text{id}_\mathcal{C}=FidC​∘F=F∘idC​=F 恒成立.

[程序] 程序设计中的范畴论 (第一部分)相关推荐

  1. 程序设计中常用的解题策略 pdf电子书

    重要提示该尊敬的用户您好,由于该程序设计中常用的解题策略pdf书受百度网盘影响无法做公共分享,只能私密分享,有不到之处请多多谅解! 百度网盘链接: http://pan.baidu.com/s/107 ...

  2. createprocess重启程序_C++_VC程序设计中CreateProcess用法注意事项,对于windows程序设计来说,启动 - phpStudy...

    VC程序设计中CreateProcess用法注意事项 对于windows程序设计来说,启动一个进程有三种方法:WinExec,ShellExecute,CreateProcess.这里仅对Create ...

  3. keil c语言 延迟程序,Keil C51程序设计中几种精确延时方法

    前几天时间在做一个基于51单片机开发板的等精度频率计,用LCD1602液晶显示的,晶振是22.1184MHZ,用得是测频率法,目的是想做到能够测试0--900KHZ的信号. 液晶显示部分花了我好几天才 ...

  4. c语言程序执行时无法输入字符串,C语言程序设计中键盘输入数据的方法分析

    1. 引言 C语言程序设计是一门实践性很强的语言课程,在程序设计过程中经常需要从键盘输入所需要的数据.C语言没有专门的输入语句,可以调用C语言编译系统提供的函数库中的库函数来实现.有些程序虽然调试成功 ...

  5. python程序设计第一章答案_Python语言程序程序设计-第一章习题解答

    作为一名非计算机专业毕业的学生,一直想学Python用来解决工作中遇到的问题,但是对计算机一直摸不到好的门路,于是买到了Python语言程序程序设计这本书,用做习题的形式,积累自己的学习成果,相信不怕 ...

  6. java程序中默认包含的是_在 Java 程序设计中,由 Java 编译器默认导入的包是( )_学小易找答案...

    [单选题]22.抑郁发作的核心症状是 ( ) [单选题]有关微卫星的描述正确的是 [单选题]下列哪一种病毒的遗传物质为RNA [判断题]演示播放时用画笔添加的标注会在保存时留下来,将会更改原来的PPT ...

  7. 程序设计中的驼峰原则

    程序设计中的驼峰原则是程序中的变量和函数名的命名原则,比如变量username要写作userName或者UserName 规则:变量名或函数名的每一个单词的首字母要大写,第一个单词的字母可大写或者小写 ...

  8. ux设计中的各种地图_移动应用程序设计中的常见UX错误

    ux设计中的各种地图 Have you ever tried a new app, only to realize you have no idea how to use it? 您是否曾经尝试过一个 ...

  9. java面试题32:Java网络程序设计中,下列正确的描述是()

    java面试题32:Java网络程序设计中,下列正确的描述是() A:Java网络编程API建立在Socket基础之上 B:Java网络接口只支持tcP以及其上层协议 C:Java网络接口只支持UDP ...

最新文章

  1. RedMonk 语言排行:Kotlin 上升 8 位,TS 快进前 10
  2. 造假露馅!曾创下融资纪录的科技公司,被曝用印度码农冒充AI,挣了1个多亿...
  3. python必背内容-python必背函数
  4. 涉密机房建设方案如何规划?
  5. 【拥抱大厂系列】面试官100%会严刑拷打的 CMS 垃圾回收器,下次面试就拿这篇文章怼回去!
  6. Leaflet中使用Leaflet.Spin插件实现地图加载等待效果
  7. 码农和程序员等的差别
  8. 腾讯视频网页下载_腾讯视频怎么下载视频
  9. [转] Asp.net mvc 3 beta 新特性介绍
  10. IIC控制设计读写EEPROM
  11. 用Visual C#调用Windows API函数
  12. JavaWeb:Filter和Listener
  13. android 版本 6.0升级包,EMUI 6.0系统刷机包
  14. 【神经网络算法入门】详细推导全连接神经网络算法及反向传播算法+Python实现代码
  15. matlab解超越函数,矩阵的超越函数Matlab提供的矩阵函数.PPT
  16. 4.live555mediaserver-第一次select
  17. 答题微信小程序实现(7):python3将题库处理成json格式的。
  18. Python Tkinter - WiFi WL Test 上位机 (自动搜索Uart、执行exe/Bat)
  19. C语言,一个分号引发的问题:Run-Time Check Failure #2 - Stack around the variable ‘class1‘ was corrupted.
  20. 51单片机中断基本概念

热门文章

  1. 软件开发项目中的成本比例
  2. 面对电信运营商HTTP劫持如何是好,投诉太折腾,不如路由器直接屏蔽广告源
  3. 福布斯2007中国富豪榜出炉 杨惠妍26岁成首富
  4. 图片太大怎么办?教你三招,快速完成图片压缩
  5. 实验1动态规划——小明打王者
  6. DNSPod十问沈添:低代码将让程序员集体失业?
  7. C++核心准则ES.40:避免复杂的表达式
  8. Excel行数多,如何快速定位到最后一行空白行?
  9. 公告(通告),消息,提醒等基本功能数据库表设计
  10. IM 即时通讯实战:环信Web IM极速集成