什么是“分类”?

9
我正在阅读程序员范畴论,但我无法确定范畴的确切含义。
让我们考虑Bool类型。 Bool是否是一个范畴,而TrueFalse则是对象(元素)?

7
顺便提一下,你现在可以在这里找到格式漂亮的文字PDF版本。 - Chris Martin
6
在第一段中,Bartosz写道:“一个范畴由对象和它们之间的箭头组成。” 因此,不,Bool(如你所描述的)不构成一个范畴 - 你需要用对象和箭头来定义一个范畴。但是,确实存在以True和False为对象的范畴,您只需要指定您想要的箭头即可。 - Chris Martin
@chi,我在哪里可以找到关于拓扑学等方面的书籍? - softshipper
1
如果你想寻找更加计算机科学导向的CT路径,可以尝试从这里获取一些书籍/论文。不过有很多材料需要阅读! - chi
4
你可以通过谷歌搜索得到无数关于类别的定义,为什么你认为在这里会得到更好的定义呢? - n. m.
显示剩余3条评论
2个回答

17

你得到许多潜在混淆的答案的一个原因是,你的问题有点像问:"假设考虑一个足球,这个足球是带有黑白多边形的'棋子'的'游戏'吗?"

答案可能是@arrowd的回答:“不是,你把足球比赛(Hask)和它的球(Bool)混淆了,而多边形(TrueFalse)并不重要。”或者,可能是@freestyle的回答:“是的,我们可以使用足球来创建一个游戏,并将一个玩家分配为黑色多边形,另一个玩家分配为白色多边形,但规则是什么?”或者,可能是@Yuval Itzchakov的回答:“从形式上讲,'游戏'是一个由一个或多个玩家、零个或多个棋子和一组规则组成等等。”

所以,让我再增加一些混乱的回答,但也许会更直接地回答你的问题。

是的,但它是一个无聊的类别

不要谈论Haskell类型Bool,让我们只谈论布尔逻辑的抽象概念和布尔值true和false。我们能够形成一个以抽象的"true"和"false"值为对象的类别吗?

答案绝对是肯定的。事实上,我们可以形成(无限)多个这样的类别。我们只需要解释"对象"是什么,"箭头"(有时被称为态射)是什么,并确保它们遵守类别的正式数学规则。

下面是一个类别: 让"对象"为"true"和"false",并且有两个"箭头":

true -> true
false -> false
Note: 不要将此->符号与Haskell函数混淆。这些箭头目前没有任何意义,它们只是对象之间的抽象连接。
现在,我知道这是一个范畴,因为它包括恒等箭头(从一个对象到其自身),并且满足组合属性,基本上是说如果我可以从a -> b -> c 跟随两个箭头,那么必须有一个直接箭头 a -> c 代表它们的“组合”。 (再次强调,当我写下a -> b -> c时,我不是在谈论函数类型 - 这些是将a连接到b,然后连接bc的抽象箭头。)无论如何,我没有足够的箭头来过多地担心这个类别的组合,因为我没有任何连接不同对象之间的“路径”。 我将其称为“离散布尔”类别。我同意它几乎没用,就像基于足球的多边形的游戏会很愚蠢一样。

是的,但它与布尔值无关

这里有一个稍微有趣一点的类别。让对象为“true”和“false”,箭头为上面两个恒等箭头加:
false -> true

这也是一种类别。它具有所有的恒等箭头,并且满足组合,因为如果忽略恒等箭头,我可以跟随的唯一有趣的“路径”是从“false”到“true”,而且没有其他地方可去,所以我仍然没有足够的箭头需要担心组合规则。

你可以在这里写下另外几个类别。看看你能不能找到一个。

不幸的是,这最后两个类别实际上与布尔逻辑的性质没有任何关系。虽然“false -> true”看起来有点像“not”操作,但是我们如何解释“false -> false”或“true -> true”,为什么不包括“true -> false”呢?

归根结底,我们可以将这些对象称为“foo”和“bar”或“A”和“B”,甚至可以不给它们命名,这些类别仍然是有效的。因此,虽然技术上这些都是以“true”和“false”为对象的类别,但它们并没有捕捉到布尔逻辑的任何有趣内容。

快速说明:多重箭头

我还没有提到的是,类别可以包含两个对象之间的多个不同箭头,因此可能会有从ab的两个箭头。为了区分它们,我可能会给它们命名,比如:

u : a -> b
v : a -> b

我甚至可以让一个箭头从 b 的标识上分离出来并指向它自己:

w : b -> b      -- some non-identity arrow

所有不同路径都必须满足组合规则。因此,由于存在路径和路径(即使它不“去”其他地方),必须有一个表示从组合后跟的箭头。它的值可能再次等于“u”,也可能是“v”,或者可能是从组合的其他箭头。描述范畴的一部分是解释所有箭头如何组合,并证明它们遵守范畴法则(单位法则和结合律,但我们不在这里担心这些法则)。

掌握了这些知识,您可以通过添加更多箭头并发明任何有关它们如何组合的规则(符合范畴法则)来创建无限数量的布尔范畴。

如果使用更复杂的对象,则会有所不同

下面是一个更有意思的范畴,它捕捉到布尔逻辑的某些“含义”。它有点复杂,所以请耐心听我讲解。

让对象为具有零个或多个布尔变量的布尔表达式:

true
false
not x
x and y
(not (y or false)) and x

我们将认为“始终相同”的表达式是相同的对象,因此y or falsey是相同的对象,因为无论y的值是什么,它们都具有相同的布尔值。这意味着上面的最后一个表达式也可以写成(not y) and x

让箭头代表将零个或多个布尔变量设置为特定值的操作。我们将用小注释标记这些箭头,使得箭头{x=false,y=true}表示按指示设置了两个变量。我们假设这些设置按顺序应用,因此箭头{x=false,x=true}对于一个表达式的影响与{x=false}相同,即使它们是不同的箭头。这意味着我们有类似下面的箭头:

{x=false} : not x -> true
{x=true,y=true} : x and y -> true

我们还有:

{x=false} : x and y -> false and y  -- or just "false", the same thing

技术上讲,标记为{x=false}的这两个箭头是不同的箭头。(它们不能是同一箭头,因为它们是连接不同对象之间的箭头。)在范畴论中,如果不同的箭头具有相同的“含义”或“解释”,就像这些箭头一样,通常会使用相同的名称来表示它们。

我们将定义箭头的组合为应用第一个箭头中的设置序列然后应用第二个箭头的设置的操作,因此组合:

{x=false}: x or y -> y     and    {y=true} : y -> true
箭头是什么:
{x=false,y=true}: x or y -> true

这是一个类别。它有针对每个表达式的恒等箭头,由不设置任何变量组成:

{} : true -> true
{} : not (x or y) and (u or v) -> not (x or y) and (u or v)

对于每一对箭头,它都定义了组合,并且这些组合遵循单位和结合律(让我们在此不必担心这个细节)。

它还代表了布尔逻辑的一个特定方面,具体来说是通过将布尔值替换为变量来计算布尔表达式的值。

嘿,看这里!一个函子!

它还有一个有趣的函子,我们可以称之为“Negate”。我不会在这里解释什么是函子。我只会说Negate通过以下方式将该类别映射到它本身:

  • 将每个对象(布尔表达式)取其逻辑否定
  • 将每个箭头映射到表示相同变量替换的新箭头

因此,箭头为:

{a=false} : (not a) and b -> b

通过Negate函子映射得到:

{a=false} : not ((not a) and b) -> not b
更简单地说,使用布尔逻辑规则:
{a=false} : a or (not b) -> not b

这是原始类别中有效的箭头。

这个函子捕捉了“否定布尔表达式”等同于“否定其最终结果”的思想,或者更一般地说,在否定表达式中替换变量的过程具有与在原始表达式中执行相同结构的特点。也许这并不太令人兴奋,但这只是一个长长的 Stack Overflow 回答,而不是关于范畴论的 500 页教科书,对吧?

现在,让我们从谈论抽象的布尔类别转向到你的具体问题,即 Haskell 类型 Bool 是否是带有对象 TrueFalse 的范畴。

上面的答案仍然适用,因为这种 Haskell 类型可以被用作布尔逻辑的模型。

然而,当人们谈论 Haskell 中的范畴时,他们通常是指一个特定的范畴 Hask,其中:

  • 对象是类型(比如 BoolInt 等)
  • 箭头是 Haskell 函数(例如 f :: Int -> Double)。最后,Haskell 语法和我们的抽象范畴语法重合 -- Haskell 函数 f 可以被看作是从对象 Int 到对象 Double 的箭头
  • 组合是普通的函数组合

如果我们谈论的是 这个 范畴,那么你问题的答案是:不,在 Hask 范畴中,Bool 是其中一种对象,而箭头是像下面这样的 Haskell 函数:

id :: Bool -> Bool
not :: Bool -> Bool
(==0) :: Int -> Bool

foo :: Bool -> Int
foo b = if b then 10 else 15

事情变得更加复杂的是,这些对象还包括函数类型,因此Bool -> Bool也是其中之一。使用此对象的箭头示例为:

and :: Bool -> (Bool -> Bool)
这是一个从对象Bool指向对象Bool->Bool的箭头。
对于这种情况,TrueFalse不是该范畴的一部分。像sqrtlength这样的函数类型的Haskell值是该范畴的一部分,因为它们是箭头,但TrueFalse是非函数类型,所以我们只需将它们从定义中省略掉。
需要注意的是,即使Bool是其中一个对象,该范畴与布尔逻辑完全无关。实际上,在该范畴中,BoolInt看起来差不多——它们只是可以有箭头离开或进入的两种类型,如果你只看Hask范畴,你永远不会知道Bool代表真和假,或者Int代表整数。
这是范畴论的一个基本方面。您使用特定的范畴来研究某个系统的特定方面。无论Bool是否是一个类别或类别的一部分都是一个模糊的问题。更好的问题是,“我感兴趣的Bool的这个特定方面是否可以表示为有用的范畴?”
我上面给出的范畴大致对应于这些可能有趣的Bool方面:
-“离散布尔”范畴将Bool表示为一个具有两个对象“true”和“false”的纯数学集合,没有其他有趣的特征。
-“false->true”类别表示布尔值的排序false < true,其中每个箭头表示运算符“<=”。
-布尔表达式范畴表示简单布尔表达式的评估模型。
-Hask表示函数组合,其输入和输出类型可为布尔类型或涉及布尔和其他类型的函数类型。

0
如果你在谈论Hask类别,那么不是的。Hask是类别,对象是Haskell类型。也就是说,Bool是一个对象,True/False甚至都没有被提到。关于Hask的描述可以在Haskell wiki上找到。还有一些讨论认为,Hask甚至不是一个合适的类别,阅读此处

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接