为什么 Haskell 的 `Functor` 实例不定义一个“类似返回”的函数?

Al *_*eed 4 haskell category-theory

在范畴论中,函子是范畴之间的态射,即将范畴中的每个对象映射A到 中的另一个对象B,并将每个态射映射C -> D到 中的各个对象B,同时保留态射的组合。因此,我们可以说函子由两个“部分”组成,一个将对象映射到对象,另一个将态射映射到态射。在Haskell中,如果我理解正确的话,Functor类型类中的每个类型都可以“映射到”,即类型的函数a -> b可以映射到函数上F a -> F b。现在为什么不存在return :: Functor f => a -> f a专门用于 的函数Functor?是否没有必要,因为我们可以简单地利用实例return中的定义Monad,因为 return 实际上只对 Monad 的函子部分起作用,还是还有其他原因?

这让我觉得很奇怪,因为如果真是这样,为什么不return包含在Functor实例中?我的意思是每个单子都有一个函子部分,所以对我来说,这是有道理的。有人能在这方面启发我吗?

Sil*_*olo 9

这是一种常见的误解,也曾经让我犯过错误。你是对的,函子有两部分:一部分将对象映射到对象,另一部分将函数映射到函数(更一般地说,箭头到箭头,但这在这里并不真正相关)。现在,当我有

instance Functor F where
    fmap f x = ...
Run Code Online (Sandbox Code Playgroud)

您已经正确地猜测将fmap函数转化为函数。然而,我们已经有了一种将对象带到对象的方法。明确地说,我们的对象不是值,而是类型。因此,“对象到对象”部分应该将一种类型映射到另一种类型。那东西叫做F。我们函子的名字字面意思是从对象到对象的映射。给定一个 type a,该类型F a是我们的函子提升的其他类型。

现在这就提出了一个公平的问题:什么是 return?它需要一个a并产生一个F a(对于 monad F)。更具体地说,给定一个固定的 monad F,签名是

return :: forall a. a -> F a
Run Code Online (Sandbox Code Playgroud)

现在请仔细阅读。这就是说“给定任何类型 a,我可以想出一个从a到 的函数F a”。也就是说,它获取我们类别中的一个对象(类型)并将其映射到我们类别中的箭头(函数)。从对象到箭头的映射称为自然变换,这正是自然变换return。

明确地说,单子是一个函子(底层类型F与 一起fmap),以及两个自然转换:

  • return,这是一个自然变换1 -> F(其中1是恒等函子),并且
  • join,这是一个自然变换F^2 -> F(其中F^2与F自身组成)

也就是说,对于任何 type a,returnhas typea -> F a且joinhas type F (F a) -> F a[1]。

return带有和 的类型类会是什么样子fmap?我不知道。我不知道有哪个 Haskell 库实现了该类型类,而且我也不完全确定这些规则会是什么样子。一个很好的猜测可能是fmap f . return === return . f,但我们实际上将其视为一个自由定理,所以这不是我们的定律。如果您或其他人在 Hackage 生态系统中的某个地方知道此类型类,请随时告诉我。


[1] Haskell 在绑定运算符方面使用“monad”的等效定义,(>>=)而不是join。它们在数学上是等价的,我在这里选择了更简单的定义。

  • @Ben,请注意,链接引用从不引用函子之间的*映射*。如果 F 和 G 都是从类别 C 到 D 的两个函子,那么“从 F 到 G”的自然变换不是从 F 到 G 的映射。相反,它是由 C 中的对象索引的箭头集合。对于C,它在类别 D 中给出了一个箭头 F(x)->G(x)。因此,它可以被视为从 C 中的对象到 D 中的箭头的映射。或者,在 Haskell 中,它可以被视为从类型(Hask 中的对象)到函数(Hask 中的箭头)的映射,将每个类型“a”映射到具有签名“F a -> G a”的函数。 (2认同)
  • @Ben 实际上,有趣的是,这基本上就是我上面所说的“自由定理”的意思。在我链接的“Theorems for Free”短文中,Wadler 解释说,任何可以在具有“参数性”的类型系统中编写并且采用类型参数的函数都是(宽松的)自然变换。 (2认同)