Haskell中的functor与范畴论中的functor有什么关系?

23
据我了解,函子是两个范畴之间的映射,例如从C中的对象到D中的对象,其中CD是范畴。在Haskell中,有一个名为Hask的范畴,其中对象是Haskell类型,态射是Haskell函数。然而,Functor类型类具有函数fmap,它将这些类型(因此是对象而不是范畴本身)之间进行映射:
fmap :: (a -> b) -> f a -> f b

f af b都是Hask中的对象。这是否意味着Haskell中每个Functor的实例都是一个自函子?如果不是,那么Functor真正代表一个函子吗?

我在这里缺少什么?类型在Haskell中也是范畴吗?

3个回答

28
Functor 的一个实例需要指定两个东西:一个类型构造器 F,其 kind 为 * -> *,也就是从 Hask 类中的对象映射到 Hask 类中的对象;以及一个函数,其类型为 (a -> b) -> (F a -> F b),也就是将 Hask 类中的箭头映射到与对象映射 F 兼容的 Hask 类中的箭头。因此,是的,Functor 的所有实例都是 endofunctors。Hackage 中提供了一些常规扩展,例如Control.Categorical.Functor

3
@Zoidberg 是的,它是 Hask 的子类别,其对象是最外层类型构造函数为 F 的类型。 - Daniel Wagner
我是否正确理解:从理论上讲,这些自函子不一定必须在类型为 * -> * 的情况下工作,我的意思是函子可以将函数 Int -> Char 映射到函数 String -> Double。据我所知,在理论上,函子适用于任何态射。但我想这并不太实际。或者我完全错了吗? - dimsuz
1
我的思路是:函子的定义是将对象映射到对象,将函数映射到函数(在Hask中)。因此,某些函子可能可以将该类别中的任何函数映射到其他函数。因此,理论上可能存在一种函子,可以将某些Int -> Char映射到String -> Double。也就是说,将a -> b映射到c -> d。或者这是不可能的吗?我知道函子将a -> b映射到F a -> F b,但是否有可能有一种函子,在另一端不使用类型构造器进行映射?再次强调,我指的至少是在理论上。 - dimsuz
1
@dimsuz 是的,这是允许的。当然,有一些规则关于映射 - 特别是函数映射必须与对象映射兼容 - 但你提出的具体建议目前似乎并没有违反该规则。现代 Haskell 甚至通过类型族 几乎 可以实现它;支持一级类型级函数的语言会自然地支持它。 - Daniel Wagner
谢谢您的澄清!我想确认我至少对这些基本要点有了更或多或少正确的理解... - dimsuz
显示剩余2条评论

19
是的,所有Functor实例都是在Hask上的自函子——事实上,所有从Hask到特定类别子集的自函子的对象类型都通过应用特定类型构造函数而得到。该类型构造函数与Functor实例相关联,并给出了对象的映射;对于态射的映射是fmap,它本身(因为我们只关心笛卡尔闭范畴上的自函子)是Hask中的一族态射。
考虑除了那些可以有Functor实例之外的其他函子确实是有意义的,例如逆变函子(从Hask到它的对偶范畴)。在Arrow中的arr函数也对应一个函子,从全部Hask映射到只有与Hask相同的对象类型的范畴,并且其态射由Arrow实例所关联的类型构造函数描述。
更进一步的泛化也是可能的(如Daniel Wagner所述),但往往变得越来越难以使用。

4
重要的一点是,你真正想要的是在Hask中进行丰富化而不仅仅是普通的函子。 Hask 是笛卡尔闭合的(虽然不是真的,但它会努力成为这样),因此它在自身的范畴中自然地变得更加丰富。
现在,丰富化的自反函子可以让你集中精力实现语言内可实现的内容:一个强化函子Hask -> Hask是一个对象层面(类型)的函数f a,并且对于每一对对象a, b,在Hask中有一个从f : Hask(a,b) -> Hask(fa,fb)的态射。当然,这只是fmap :: (a -> b) -> f a -> f b

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