为什么Haskell函子在其目标类别中仅具有派生类型?


12

在Haskell中,Functor类型类函子的定义如下(例如,参见Haskell Wiki):

class Functor (f :: * -> *) where
  fmap :: (a -> b) -> f a -> f b 

据我了解(请纠正我,如果我错了),这样的仿函数只能作为目标类别使用类型构造一个类别构成,例如[]Maybe等等。另一方面,人们可能会想到有任何类别的函子作为函子的目标,例如所有Haskell类型的类别。例如,Int可以是函子的目标类别中的对象,而不仅仅是Maybe Intor [Int]

限制Haskell函子的动机是什么?


4
简单?Haskell没有一流的类型函数,因此所有函数实际上只是类型构造函数。
Daniel Gratzer 2014年

2
@jozefg:原谅我的无知:什么是“一流类型函数”?
乔治

4
因此,在该功能中,我们会折腾f吗?在您的情况下,f应该像普通的Haskell函数一样,将类型映射到类型。在Haskell中,唯一拥有类型的* -> *是类型构造函数。类型族更为笼统,但必须始终加以全面使用
Daniel Gratzer 2014年


@jozefg:我偶尔会反复考虑这个问题。我认为Haskell限制不影响函子的表达能力。例如,假设我们有一个与列表函子同构的函子,但没有映射,例如Int-> [Int]但Int-> <不使用类型构造函数的特殊类型>。然后,我猜可以证明<不使用类型构造函数的奇特类型>与[Int]同构。因此,选择使用类型构造函数定义的对象很方便,并且不会牺牲表达能力。
乔治

Answers:


1

完全没有限制!当我开始学习类型构造函数的类别理论基础时,这一点也使我感到困惑。我们将解决这个问题。但是首先,让我澄清一些混乱。这两个引号:

这样的函子只能将使用类型构造函数构造的类别作为目标类别

可能会想到具有任何类别作为函子目标的函子,例如所有Haskell类型的类别

说明您误解了函子是什么(或者至少是您误用了术语)。

函子不构成类别。函子是类别之间的映射。函数将源类别中的对象和形态(类型和函数)带到目标类别中的对象和形态。

请注意,这意味着函子实际上是对映射:对象F_obj上的映射和态射F_morph上的映射。在Haskell中,函子的对象部分F_obj是类型构造函数的名称(例如List),而形态学部分是函数fmap(取决于Haskell编译器来整理fmap我们在任何给定表达式中引用的内容)。因此,我们不能说这List是一个函子。只的组合Listfmap是一个算符。尽管如此,人们还是滥用符号。程序员List将函子称为函子,而类别理论家则使用相同的符号来引用函子的两个部分。

此外,在编程中,几乎所有的函子都是函子,即源类别和目标类别是相同的-我们语言中所有类型的类别。我们将此类别称为Type。一个endofunctor ˚F类型映射Ť到另一种类型的FT和功能笔- >取值给另一个函数FT - > FS。当然,此映射必须遵守函子定律。

使用List为例:我们有一个类型构造List : Type -> Type和功能fmap: (a -> b) -> (List a -> List b),共同构成一个仿函数。Ť

最后一点需要澄清。编写List int不会创建新的整数列表类型。这种类型已经存在。这是我们类别Type中的一个对象。List Int只是引用它的一种方式。

现在,您想知道为什么函子无法将类型映射到例如IntString。但是,可以!只需使用身份函子即可。对于任何类别C,身份仿函数都将每个对象映射到自身,并将态射映射到自身。验证此映射是否满足函子定律很简单。在Haskell中,这将是一个id : * -> *将每个类型映射到自身的类型构造函数。例如,id int计算为int

而且,甚至可以创建恒定的函子,将所有类型映射到一个类型。例如,functor ToInt : * -> *ToInt a = int对于所有类型为)a,并将所有态射映射到整数标识函数: fmap f = \x -> x


感谢您的回答,这个问题已有两年多了。“ functor不会构造类别。”:我没有这么说。我说过函子映射两个类别,据我所知,目标类别必须具有form形式f a,在f我所知的地方,它是类型构造函数。从类别理论中我记得,这一定是某种规范的表示形式(类别中的初始对象?也许我在滥用术语。)无论如何,我都会仔细阅读您的答案。非常感谢。
乔治(Giorgio)

@乔治,哎呀,我没注意到哈哈多大。它只是出现在“未回答的问题”中。我不确定“规范表示”是什么意思。据我所知(这里我可能是错的),函子和初始/终止对象之间没有关系。
gardenhead

我的意思是:en.wikipedia.org/wiki/Initial_algebra(请参阅在计算机科学中使用)。在Haskell中,函子是在代数数据类型上定义的。这种函子的目标对象是初始代数。初始代数与使用值构造函数构建的一组术语同构。例如,用于列表,[]:。我的意思是规范表示。
Giorgio

是的,我知道什么是初始对象,归纳数据类型是类别的F代数中的初始对象。您是正确的,许多类型构造函数都是归纳定义的。但这不是严格必要的。例如,将(_, int)类型a带到产品类型(a, int)并将功能f : 'a -> 'b带到的函子g : 'a * int -> 'a * int不是归纳的。
gardenhead

您的意思是:“需要......一个函数f : 'a -> 'bg : 'a * int -> 'b * int
乔治
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.