Haskell的Functor类型类为何未定义类似return的函数?
Functor类型类没有定义return? 核心原因很简单:不是所有合法的Functor都能定义符合法则的return(或pure)操作。我们从范畴论定义和Haskell的类型类层级两方面拆解:
1. 范畴论里的函子不需要"单位映射"
从范畴论的定义来看,函子只需要满足两个核心要求:
- 把源范畴的每个对象映射到目标范畴的对象
- 把源范畴的每个态射映射到目标范畴的态射,且保持态射的复合和恒等态射
这里完全没有要求函子必须提供一个"从单个元素到函子包裹元素"的映射——这种映射属于**幺半群函子(Monoidal Functor)**的额外结构,也就是Haskell里Applicative类型类对应的概念,而Monad又是Applicative的进一步扩展。
2. Haskell中存在无法定义合法return的Functor实例
举个典型的例子:Const函子
newtype Const e a = Const e
它的Functor实例是合法的:
instance Functor (Const e) where fmap _ (Const e) = Const e
但你没法定义一个符合法则的return :: a -> Const e a:因为Const e a的构造只依赖于e,和a完全无关。如果强行写一个忽略a的实现,会违反后续Applicative的核心法则(比如pure id <*> v = v),导致结构逻辑不成立。
再比如(-> r)读者函子,虽然能定义return x = \_ -> x,但这是因为它同时具备Applicative和Monad的额外结构,并非Functor本身的必备能力。
3. Haskell的类型类层级设计:从弱到强
Haskell的类型类是分层递进的:
Functor:最基础,只需要fmap,描述"可映射"的结构Applicative:继承Functor,增加pure(对应return)和<*>,描述"可批量应用函数"的结构Monad:继承Applicative,增加>>=,描述"可链式绑定"的结构
return本质上是pure的别名,属于Applicative层级的操作。把它放到Functor里会打破这个分层,导致很多合法的Functor(比如Const)无法成为Functor实例,这显然不合理。
你之所以觉得"每个Monad都包含函子部分",是因为Monad是Functor的扩展,但反过来,不是所有Functor都是Monad(甚至不是所有Functor都是Applicative),所以不能把上层结构的操作下放到基础层级。
内容的提问来源于stack exchange,提问作者Al Sneed

