问题描述
编程中是否使用了通用函子(不限于endofunctor)?
我了解使用endofunctor的原因是使结构简单,如monoid或monad。
我也最终理解,所有的值都归结为一种编程语言(例如Hask)的类别,但是我在这里谈论的是相同类别的字符串,数字,布尔值或函数之间的endofunctor
相关问题:
Are all Haskell functors endofunctors?
Differences between functors and endofunctors
解决方法
首先,是。
例如,我们都知道可以通过以下方式将一个monoid定义为一个单对象类别:
- 箭头成为元素
- 单个对象没有意义
- 要成为运算符的构成(在Haskell中为
(<>)
) - id箭头为身份(在Haskell中为
mempty
)。
从这个意义上说,两个类半同形词之间的同构成为两个类别之间的函子。
现在,假设类型A
和B
都是类半体符号;它们之间的函子只是同态函数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 a
,fmap f x = Diag (f x) (f x)
每个类型A
到其正方形A * A
。但是, Hask * Hask 仍然是 Hask 的子类别,因此我们可以说这也是一个终结者。
简短答案:是,Haskell中的类别“较小”,您可以在它们之间定义函子(而不仅仅是endofuncunctors)。它们是否有用是另一个问题。
这是我多年来一直想知道的事情。当前的问题促使我对此采取了行动。我目前第三次浏览Bartosz Milewski的Category Theory for Programmers。我不确定我是否正确,因此,希望您能提供反馈。
帽子
如果我理解正确, Hask 本质上是类型的类别(〜 sets 的类别),底部是 em>(⊥)表示非终止计算。下面是说明它的尝试:
Hask 中的每个对象是类型,例如Int
,Bool
,String
或您自己的自定义类型,例如Reservation
,Order
等。类型可以视为 set ;例如Bool
是包含True
和False
的集合,String
是所有字符串的集合,依此类推。显然,其中许多集合(例如String
)都是无限。
此外,还有一个特殊的底部对象。
您可以将类型映射到其他类型,但是不能映射到 Hask 之外的其他内容,因为 Hask 包含所有类型和表达式:
在这里,我通过复制 Hask 说明了从 Hask 到 Hask 的映射,但实际上,这两个类别只是两张相同的图像。
函子是不仅映射对象,而且还映射对象之间的态射的映射。关于这一点已经有很多话了,所以我在这里要说的唯一一点是,由于 Has 和 Hask 之间的仿函数不会离开类别,因此它们是仿函数内部 Hask ,因此是终结者。这就是Haskell中的Functor
类型类。
单位类别
那么,问题是: Hask 中是否存在“较小”类别?
据我所知:是的,无限多个。 存在的最简单的类别之一是具有单个对象的类别,除了身份态射影外没有其他射态: 在Haskell中,这可能是 unit ( 上面的 Unit 类别只是free category的示例。自由类别是从有向图构造的类别。这是另一张图: 这个有两个顶点和两个边。我们可以通过将顶点解释为对象,将边缘解释为射态来从该图构造一个类别。我们还必须为每个对象添加同一性词素以及词素的组成。 在编程中,具有两个对象的集合等效于只有两个居民的类型。您可以为这些值指定不同的名称,但是这种类型对于 我们可以定义以上两个类别之间的映射吗? 是的,我们可以通过将 Unit 嵌入“较大”类别中来实现。我们可以通过任意选择一个对象来做到这一点: 存在另一个拾取其他对象的函子。 这显然是类别之间的映射 ,因此不是endofunctor。不过,它是合适的函子吗? 要成为函子,映射不仅必须将对象映射到对象,而且还必须将射态射向射态。这里也是这种情况,因为 Unit 仅具有身份同构。因此,我们还将身份同构映射到我们选择的目标对象上的身份同构。 单位中唯一可能的组合是 我只涉猎类别理论几年了,但是我认为这是一个合适的函子。 Haskell定义了一个名为Category的类型类。它不太适合上面的 Unit 类别或上面的自由类别示例,因为它假定 类似于Const仿函数,此类型定义了类型变量,然后将其忽略。就像 我们可以将 这是一个适当的类别吗?它遵守法律吗? 我们可以使用方程式推理来证明它可以做到: 这对我来说很好。 上面的免费类别示例怎么样?像上面的 我将布尔型同态称为 要对所讨论的类别进行建模,只允许使用 我们可以将 实际上,这是可能的。我不会证明这是一个类别,因为它实际上只是专用于 现在让我们在 我们还需要支持 为了实现更通用的 这足以定义实例: 这将 使用起来有点尴尬,但是有可能: Haskell无法确定 编程中是否存在函子(不仅是endofuncunctors)?是的,他们有。 它们有用吗?在我看来,如果您斜视一下,这些函子只是“正常”功能的一部分。上面的函子的简化版本是: 这只是正常功能。 我必须更多地考虑这样查看时是否还有更有用的应用程序。()
)类型的图片。 ()
是 Hask 的一部分,但您也可以将其本身视为一个类别。我们称之为 Unit 。免费类别
Bool
总是同构的。 Functor
id ∘ id
,id ∘ id ∘ id
,依此类推。这些都映射到目标对象上的id ∘ id
,id ∘ id ∘ id
等。 Haskell类别类型类
Category
是一种类型较高的类型(即,它涉及 types )。不过,让我们看看是否可以将 Unit 和上面的免费类别添加到Category
中,并用其制成函子。 单位为
Category
Category
的实例必须是类型较高的类型(即cat a b
),因此我们不能仅仅将()
变成Category
实例。但是,我们可以为其定义更高种类的同构:data U a b = U deriving (Eq,Show)
()
一样,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
,因为事实就是如此。两个对象(True
和False
)之间的边对应于拾取 other 对象,这等效于内置的not
函数。 / p>
other
和id
的词素,因此应禁止使用其他功能Bool -> Bool
(例如\_ -> True
)。因此,定义Bendo
的模块不应导出数据构造函数。Bendo
设为Category
实例吗?
instance Category Bendo where
id = Bendo id
(Bendo f) . (Bendo g) = Bendo (f . g)
->
的{{1}}类别实例。 Functor
(->) Bool Bool
和U
之间定义一个函子。为此,我们可以使用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
> (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
。结论
True