在范畴论中,函子是范畴间的态射,即它将范畴A
中的每一个对象映射到范畴B
中的另一个对象,并将每一个态射C -> D
映射到范畴B
中各自的对象上,同时保持态射的复合。所以我们可以说一个函子由两部分组成,一部分将对象映射到对象,另一部分将态射映射到态射。在Haskell中,如果我理解正确的话,Functor
类型类中的每个类型都可以"映射到",也就是说,类型a -> b
的函数可以映射到函数F a -> F b
。为什么不存在return :: Functor f => a -> f a
函数,专门针对Functor
呢?是否没有必要,因为我们可以简单地利用Monad
实例中的return
的定义,因为return实际上只在Monad的函子部分工作,或者还有其他原因?
这让我觉得很奇怪,因为如果是这样的话,为什么return
不包含在Functor
实例中呢?我的意思是每个单子都有一个函子部分,所以对我来说,这是有意义的。在那件事上有人能指点我吗?
这是一个常见的误解,也是一个曾经让我绊倒的误解。你是对的,函子有两个部分:一个是对象到对象的映射,另一个是函数到函数的映射(更一般地说,是箭头到箭头,但在这里不是很相关)。现在,当我有
instance Functor F where
fmap f x = ...
您已经正确地推测出fmap
将函数转换为函数。然而,我们已经有一种方法可以将对象传递给对象。明确地说,对象不是值,而是类型。所以"对象对对象"Part应该将一个类型映射到另一个类型。这个东西叫做F
。函子的名字从字面上看就是对象到对象的映射。给定类型a
,则F a
类型是函子提升的另一类型。
现在提出了一个公平的问题:是什么return
?它接受一个a
并产生一个F a
(对于单子F
)。更具体地说,给定一个固定的单子F
,签名是
return :: forall a. a -> F a
现在仔细读一下。这就是说"给定任何类型a
,我可以想出一个从a
到F a
的函数"。也就是说,它接受类别中的对象(类型),并将其映射到类别中的箭头(函数)。从对象到箭头的映射称为自然变换,这正是return
的含义。
绝对地说,单子是一个函子(基础类型F
和fmap
),以及两个自然变换:
return
,这是一个自然变换1 -> F
(其中1
是单位函子),和join
,这是一个自然变换F^2 -> F
(其中F^2
是F
与自身组合)
即对于任意类型a
,return
的类型为a -> F a
,join
的类型为F (F a) -> F a
[1]。
具有return
和fmap
的类型类看起来像什么?我不确定。我不知道Haskell库实现了这个类型类,我也不完全确定规则是什么样子的。一个很好的猜测可能是fmap f . return === return . f
,但我们实际上得到了一个自由定理,所以这不是我们的定律。如果您或其他人在Hackage生态系统中知道这个类型类,请随时告诉我。
[1]Haskell使用了"monad"根据绑定操作符(>>=)
而不是join
。它们在数学上是等价的,我在这里选择了更简单的定义。