什么是类别?

时间:2017-10-01 08:24:08

标签: scala haskell category-theory

我正在阅读Category Theory for Programmers,我无法弄清楚究竟是什么类别。

让我们考虑Bool类型。 Bool是一个类别,TrueFalse是对象(居民)吗?

2 个答案:

答案 0 :(得分:13)

你得到很多可能令人困惑的答案的一个原因是你的问题有点像问:"让我们考虑一下足球。足球是一场比赛吗?黑色和白色多边形的片段是'?"

答案可能是@ arrowd的回答:"不,你将足球比赛(Hask)与球(Bool)混为一谈,多边形(TrueFalse)并不重要。"或者,它可能是@自由式的答案:"是的,我们当然可以使用足球创建一个游戏并将一个玩家分配给黑色多边形而另一个玩家分配白色多边形,但规则是什么是&#34?;或者,它可能是@Yuval Itzchakov的答案:"正式的,一场游戏'是一个或多个玩家的集合,零件或多件,以及一系列规则,如等等。"

所以,让我再加上一个(非常长的)答案的混乱,但也许它会更直接地回答你的问题。

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

不要谈论Haskell类型Bool,而是谈谈布尔逻辑的抽象概念和布尔值true和false。我们可以用抽象值形成一个类别" true"和"假"作为对象?

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

这是一个类别:让"对象" be" true"并且" false",并且有两个"箭头":

true -> true
false -> false

注意:请勿将此->符号与Haskell函数混淆。这些箭头不是"意思是"还有什么,它们只是对象之间的抽象连接。

现在,我知道这是一个类别,因为它包含两个标识箭头(从一个对象到它自身),它满足组合属性,基本上说如果我可以跟随a -> b -> c中的两个箭头,那么那里必须是代表他们"组成的直接箭头a -> c"。 (再次,当我写a -> b -> c时,我在这里讨论函数类型 - 这些是连接a的抽象箭头到b然后bc。)无论如何,我没有足够的箭头来担心这个类别的构图太多,因为我没有任何"路径"不同对象之间。我将其称为" Discrete Boolean"类别。我同意它几乎没用,就像一个基于足球多边形的游戏会非常愚蠢。

是的,但它与布尔值无关

这是一个稍微有趣的类别。让对象成为" true"和" false",并让箭头成为上面的两个身份箭头加上:

false -> true

这也是一个类别。它具有所有的身份箭头,并且它满足构图,因为忽略了身份箭头,唯一有趣的"路径"我可以跟随来自" false"真的"以及其他任何地方都没有,所以我仍然没有足够的箭来担心构图规则。

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

不幸的是,最后两个类别与布尔逻辑的属性没有任何关系。确实false -> true看起来有点像not操作,但是我们如何解释false -> falsetrue -> true,以及为什么没有true -> false a {1}}那里也有?

最终,我们可以很容易地调用这些对象" foo"和" bar"或" A"和" B"或者甚至不打算给它们命名,这些类别也同样有效。所以,虽然技术上这些类别是" true"和"假"作为对象,他们不会捕获有关布尔逻辑的任何有趣内容。

快速放弃:多个箭头

我还没有提到的是,类别可以在两个对象之间包含多个不同的箭头,因此可能有两个箭头从bu : a -> b v : a -> b 。为了区分它们,我可以给它们命名,例如:

b

我甚至可以将{em>分开从w : b -> b -- some non-identity arrow 到自身的身份:

u : a -> b

必须通过所有不同的路径来满足构图规则。所以,因为路径w : b -> b和路径u(即使它没有"去"其他地方),也必须有箭头表示来自w的{​​{1}}后跟a -> b的组成。它的值可能等于" u"再次,或可能是" v",或者可能是来自a -> b的其他箭头。描述一个类别的部分原因在于解释所有箭头如何构成并证明它们遵守类别法(单位法和联想法,但在这里不要担心这些法律)。

有了这些知识,您可以创建无限数量的布尔类别,只需在任何地方添加更多箭头,并根据类别法律发明您应该如何编写的任何规则。

排序,如果您使用更复杂的对象

这是一个更有趣的类别,它捕获了一些"含义"布尔逻辑解释起来很复杂,所以请耐心等待。

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

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

我们会考虑表达式总是相同的#34;要成为同一个对象,因此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}的两个箭头是不同的箭头。 (它们可以是相同的箭头,因为它们是不同对象之间的箭头。)在类别理论中,如果它们具有相同的&#,则对于不同的箭头使用相同的名称是非常常见的#&#。 34;含义"或"解释",就像这些一样。

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

{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)

它定义了每对箭头的构图,并且构图遵循单位和关联法则(同样,让我们​​不要担心这里的细节)。

并且,它代表布尔逻辑的一个特定方面,特别是通过将布尔值替换为变量来计算布尔表达式的值。

<嗨>嘿,看!一个Functor!

它还有一个有趣的函子,我们可以称之为&#34;否定&#34;。我不会解释这里的仿函数是什么。我只是说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

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

这个仿函数捕获了&#34;否定布尔表达式的想法&#34;相当于&#34;否定它的最终结果&#34;,或者更一般地说,在否定表达式中替换变量的过程与对原始表达式的变量具有相同的结构。也许这不是太令人兴奋,但这只是一个很长的Stack Overflow答案,而不是一本500页的分类理论教科书,对吗?

Bool作为Hask类别

的一部分

现在,让我们从讨论抽象布尔类别转到您的具体问题,Bool Haskell 类型是否是包含对象True和{的类别{1}}。

上面的答案仍然适用,只要这个Haskell类型可以用作布尔逻辑的模型。

但是,当人们谈论Haskell中的类别时,他们通常会讨论特定类别False,其中:

  • 对象是类型(如HaskBool等)。
  • 箭头是Haskell函数(如Int)。 最后,Haskell语法和我们的抽象类别语法重合 - Haskell函数f :: Int -> Double可以被认为是从对象f到对象{{1}的箭头})。
  • 组成是常规功能组合

如果我们在讨论类别,那么您的问题的答案是:不,在Int类别中,Double是其中一个对象,箭头是Haskell函数,如:

Hask

为了使事情变得更复杂,对象包括函数类型,因此Bool是其中一个对象。使用此对象的箭头的一个示例是:

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) 的箭头。

在这种情况下,BoolBool -> Bool不是该类别的一部分。函数类型的Haskell值(如TrueFalse)属于类别,因为它们是箭头,但sqrtlength是非函数类型,因此我们只是将它们排除在定义之外。

类别理论

请注意,最后一个类别,就像我们查看的第一个类别一样,与布尔逻辑完全无关,即使True是其中一个对象。事实上,在此类别中,FalseBool看起来大致相同 - 它们只是两种可以让箭头离开或进入它们的类型,而且您永远不会知道如果您只是查看Bool类别,则Int是关于真假的,或Bool代表整数。

这是范畴理论的一个基本方面。您使用特定类别来研究某个系统的特定方面。 Int是一个类别还是类别的一部分是一个模糊的问题。更好的问题是,Hask的这个特殊方面是我对可以表现为有用类别的东西感兴趣吗?&#34;

我上面给出的类别大致对应Bool的这些可能有趣的方面:​​

  • &#34;离散布尔&#34; category将Bool表示为两个对象的简单数学集合,&#34; true&#34;并且&#34; false&#34;,没有其他有趣的功能。
  • &#34; false - &gt;真&#34; category表示布尔值的排序Bool,其中每个箭头代表运算符&#39;&lt; =&#39;。
  • 布尔表达式类别表示简单布尔表达式的评估模型。
  • Bool表示函数的组合,其输入和输出类型可以是布尔类型或涉及布尔值和其他类型的函数类型。

答案 1 :(得分:0)

如果您正在谈论Hask类别,那么不。 Bool是类别,对象是Haskell类型。也就是说,True是一个对象,False / Hask甚至在这里都没有被讨论过。 Hask的描述可以在Haskell wiki找到。还有一些会谈,{{1}}甚至不是一个合适的类别,read this