为什么 Haskell 的"Functor"实例没有定义一个"return-like"函数?



在范畴论中,函子是范畴间的态射,即它将范畴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,我可以想出一个从aF a的函数"。也就是说,它接受类别中的对象(类型),并将其映射到类别中的箭头(函数)。从对象到箭头的映射称为自然变换,这正是return的含义。

绝对地说,单子是一个函子(基础类型Ffmap),以及两个自然变换:

  • return,这是一个自然变换1 -> F(其中1是单位函子),和
  • join,这是一个自然变换F^2 -> F(其中F^2F与自身组合)

即对于任意类型a,return的类型为a -> F a,join的类型为F (F a) -> F a[1]

具有returnfmap的类型类看起来像什么?我不确定。我不知道Haskell库实现了这个类型类,我也不完全确定规则是什么样子的。一个很好的猜测可能是fmap f . return === return . f,但我们实际上得到了一个自由定理,所以这不是我们的定律。如果您或其他人在Hackage生态系统中知道这个类型类,请随时告诉我。


[1]Haskell使用了"monad"根据绑定操作符(>>=)而不是join。它们在数学上是等价的,我在这里选择了更简单的定义。

最新更新