编程中是否有任何通用函子不限于endofunctor使用? 右身份左身份关联性

问题描述

编程中是否使用了通用函子(不限于endofunctor)?

我了解使用endofunctor的原因是使结构简单,如monoid或monad。

我也最终理解,所有的值都归结为一种编程语言(例如Hask)的类别,但是我在这里谈论的是相同类别的字符串,数字,布尔值或函数间的endofunctor

相关问题:

Are all Haskell functors endofunctors?

Differences between functors and endofunctors

解决方法

首先,

例如,我们都知道可以通过以下方式将一个monoid定义为一个单对象类别:

  • 箭头成为元素
  • 单个对象没有意义
  • 要成为运算符的构成(在Haskell中为(<>)
  • id箭头为身份(在Haskell中为mempty)。

从这个意义上说,两个类半同形词之间的同构成为两个类别之间的函子。

现在,假设类型AB都是类半体符号;它们之间的函子只是同态函数f :: A -> B,该同构函数将每个A映射到B,从而保留了组成。

但是,等等,f :: A -> B甚至不是Functor(请注意,我在这里使用等宽字体)!

不,它不是Haskell中的Functor,但从数学意义上讲,它仍然是函子。

因此,要强调一下,我再说一遍:在编程中使用了“非内在”仿函数,并且可能比内在仿函数更频繁地使用。

这里的要点是类别理论是一种高度抽象的理论-它提供了抽象具体对象的概念。我们可以将这些概念定义为在不同上下文中表示不同的事物。

设置(或设置设置的子类别)只是这些无限定义之一,使得

  • 箭头成为功能
  • 要成为类型(或集合)的对象
  • 组成为功能组成(.)
  • id箭头用作id函数。

将此“分类宇宙”定义与上面的“分类monoid”定义进行比较-恭喜,您已经知道类别有两种不同的用法!

最后,请记住类别理论本身仅仅是一些抽象。抽象本身毫无意义,也没有任何用处。我们将它们与真实事物联系在一起,只有这样,它们才能为我们带来便利。通过具体的示例理解抽象概念,但切勿将这些概念本身简化为任何具体的事物(例如,切勿将函子简化为仅属于“分类宇宙”之间的函子(例如 Has Set 等)!)。

P.S。如果您问“是否有函子将 Hask 发送到Haskell的另一个类别?”那么答案可能是是或否。例如,您可以定义类别 Hask * Hask ,以包含任意两种类型的笛卡尔积,以及发送的函子data Diag a = Diag a afmap f x = Diag (f x) (f x)每个类型A到其正方形A * A。但是, Hask * Hask 仍然是 Hask 的子类别,因此我们可以说这也是一个终结者。

,

简短答案:,Haskell中的类别“较小”,您可以在它们之间定义函子(而不仅仅是endofuncunctors)。它们是否有用是另一个问题。

这是我多年来一直想知道的事情。当前的问题促使我对此采取了行动。我目前第三次浏览Bartosz Milewski的Category Theory for Programmers。我不确定我是否正确,因此,希望您能提供反馈。

帽子

如果我理解正确, Hask 本质上是类型的类别(〜 sets 的类别),底部是 em>(⊥)表示非终止计算。下面是说明它的尝试:

The category of Hask illustrated as a set of types,plus bottom

Hask 中的每个对象类型,例如IntBoolString或您自己的自定义类型,例如ReservationOrder等。类型可以视为 set ;例如Bool是包含TrueFalse的集合,String是所有字符串的集合,依此类推。显然,其中许多集合(例如String)都是无限。

此外,还有一个特殊的底部对象。

您可以将类型映射到其他类型,但是不能映射到 Hask 之外的其他内容,因为 Hask 包含所有类型和表达式:

Mapping from Hask to Hask

在这里,我通过复制 Hask 说明了从 Hask Hask 的映射,但实际上,这两个类别只是两张相同的图像。

函子是不仅映射对象,而且还映射对象之间的态射的映射。关于这一点已经有很多话了,所以我在这里要说的唯一一点是,由于 Has Hask 之间的仿函数不会离开类别,因此它们是仿函数内部 Hask ,因此是终结者。这就是Haskell中的Functor类型类。

单位类别

那么,问题是: Hask 中是否存在“较小”类别?

据我所知:是的,无限多个。

存在的最简单的类别之一是具有单个对象的类别,除了身份态射影外没有其他射态:

Unit category

在Haskell中,这可能是 unit ())类型的图片。 () Hask 的一部分,但您也可以将其本身视为一个类别。我们称之为 Unit

免费类别

上面的 Unit 类别只是free category的示例。自由类别是从有向图构造的类别。这是另一张图:

Graph with two vertices and two edges

这个有两个顶点和两个边。我们可以通过将顶点解释为对象,将边缘解释为射态来从该图构造一个类别。我们还必须为每个对象添加同一性词素以及词素的组成。

在编程中,具有两个对象的集合等效于只有两个居民的类型。您可以为这些值指定不同的名称,但是这种类型对于Bool总是同构的。

Functor

我们可以定义以上两个类别之间的映射吗?

是的,我们可以通过将 Unit 嵌入“较大”类别中来实现。我们可以通过任意选择一个对象来做到这一点:

Functor between Unit and the free category example

存在另一个拾取其他对象的函子。

这显然是类别之间的映射 ,因此不是endofunctor。不过,它是合适的函子吗?

要成为函子,映射不仅必须将对象映射到对象,而且还必须将射态射向射态。这里也是这种情况,因为 Unit 仅具有身份同构。因此,我们还将身份同构映射到我们选择的目标对象上的身份同构。 单位中唯一可能的组合是id ∘ idid ∘ id ∘ id,依此类推。这些都映射到目标对象上的id ∘ idid ∘ id ∘ id等。

我只涉猎类别理论几年了,但是我认为这是一个合适的函子。

Haskell类别类型类

Haskell定义了一个名为Category的类型类。它不太适合上面的 Unit 类别或上面的自由类别示例,因为它假定Category是一种类型较高的类型(即,它涉及 types )。不过,让我们看看是否可以将 Unit 和上面的免费类别添加到Category中,并用其制成函子。

单位Category

Category的实例必须是类型较高的类型(即cat a b),因此我们不能仅仅将()变成Category实例。但是,我们可以为其定义更高种类的同构:

data U a b = U deriving (Eq,Show)

类似于Const仿函数,此类型定义了类型变量,然后将其忽略。就像()一样,U类型只有一个值,也称为U。 (锻炼:证明U()是同构的。)

我们可以将U设为Category实例:

instance Category U where
  id = U
  U . U = U

这是一个适当的类别吗?它遵守法律吗?

我们可以使用方程式推理来证明它可以做到:

右身份

  U . id
= { definition of (.) }
  U

左身份

  id . U
= { definition of (.) }
  U

关联性

  U . (U . U)
= { definition of (.) }
  U . U
= { redundant brackets }
  (U . U)
= { definition of (.) }
  (U . U) . U

这对我来说很好。

免费类别示例为Category

上面的免费类别示例怎么样?像上面的U类型一样,这个很小的类别不能是参数多态的,但是我们可以再次定义一个幻像类型:

data Bendo a b = Bendo { runB :: Bool -> Bool }

other :: Bendo a b
other = Bendo not

我将布尔型同态称为Bendo,因为事实就是如此。两个对象(TrueFalse)之间的边对应于拾取 other 对象,这等效于内置的not函数。 / p>

要对所讨论的类别进行建模,只允许使用otherid的词素,因此应禁止使用其他功能Bool -> Bool(例如\_ -> True)。因此,定义Bendo的模块不应导出数据构造函数。

我们可以将Bendo设为Category实例吗?

instance Category Bendo where
  id = Bendo id
  (Bendo f) . (Bendo g) = Bendo (f . g)

实际上,这是可能的。我不会证明这是一个类别,因为它实际上只是专用于->的{​​{1}}类别实例。

Functor

现在让我们在(->) Bool BoolU之间定义一个函子。为此,我们可以使用Control.Categorical.Functor中给出的Bendo的更一般定义。为了使所有这些工作正常进行,我不得不隐藏Functor中给出的常用定义:

Prelude

我们还需要支持import Control.Category import Control.Categorical.Functor import Prelude hiding (id,(.),Functor(..))

MultiParamTypeClasses

为了实现更通用的{-#LANGUAGE MultiParamTypeClasses #-} 类型类,我们需要一种类型更高的类型。再次,让我们为此目的生成另一个幻像类型:

Functor

这足以定义实例:

data Embed a = Embed deriving (Eq,Show)

这将instance Functor Embed U Bendo where fmap U = Bendo id 映射到U中的身份运动。

使用起来有点尴尬,但是有可能:

Bendo

Haskell无法确定> (runB $ (fmap U :: Bendo (Embed a) (Embed b))) False False > (runB $ (fmap U :: Bendo (Embed a) (Embed b))) True True 的类型,因此您必须告诉它。告诉您结果应为fmap U类型后,Bendo (Embed a) (Embed b)会将fmap映射到恒等态,然后可以通过将U应用于任一{{1 }}或runB

结论

编程中是否存在函子(不仅是endofuncunctors)?是的,他们有。

它们有用吗?在我看来,如果您斜视一下,这些函子只是“正常”功能的一部分。上面的函子的简化版本是:

True

这只是正常功能。

我必须更多地考虑这样查看时是否还有更有用的应用程序。