【问题标题】:Why is there a distinction between co and contravariant functors in Haskell but not Category Theory?为什么 Haskell 中的 co 和逆变函子有区别,但范畴论没有区别?
【发布时间】:2019-05-20 03:49:18
【问题描述】:

This answer from a Category Theory perspective 包含以下语句:

...事实上,co 和逆变函子之间没有真正的区别,因为每个函子都只是一个协变函子。

...

更详细地说,从 C 类到 D 类的逆变函子 F 只不过是 F : Cop→D 类型的(协变)函子,从 C 的相反类别到D类。

另一方面,Haskell 的FunctorContravariant 只需要分别为实例定义fmapcontramap。这表明,从 Haskell 的角度来看,存在 Contravariant 但不是 Functors 的对象(反之亦然)。

所以似乎在范畴论中“co 和逆变函子之间没有真正的区别”,而在 Haskell 中,ContravariantFunctor 之间存在区别。

我怀疑这种差异与 Haskell 中发生在 Hask 中的所有实现有关,但我不确定。

我认为我自己理解类别理论和 Haskell 的每一个观点,但我很难找到一种将两者联系起来的直觉。

【问题讨论】:

  • 我已经很久没有学习范畴论了(无论如何,它从来都不是我专门研究的领域),但我认为可以肯定地说协变和协变之间“没有区别”是不正确的逆变函子。只是一个可以用另一个来定义,所以用数学术语来说差异是微不足道的。 (这并不是说它在应用到其他数学领域时不会产生重要的影响。)现在我对 Haskell 比较陌生,不熟悉逆变类,但我想它忠实地再现了数学定义.
  • 所以想多了,FunctorContravariant 在 Haskell 中不是“相同”的原因可能只是因为 Hask 的相反类别(其中一个来自 @ 的态射987654334@ 到bb -> a 类型的函数表示)并不是一件特别自然的事情。这是因为 Haskell 实际上只涉及 一个 类别,函子是 Hask 上的内函子,而数学类别理论是关于各种不同类别的关系(即函子之间)在他们自己的权利)。
  • 如果没有逆变函子的概念,您也可以轻松过关,因为任何这样的函子都只是给定适当源类别的协变函子。不过,定义 Contravariant 类型类比定义 HaskellOP 更容易。

标签: haskell terminology functor category-theory


【解决方案1】:

这是为了方便。

我们可以使用more general Functor 类,并为 Hask 上的 endofunctors(对应于我们现有的Functor)和从 Hask^op 到 Hask 的函子(对应于我们现有的Contravariant)定义实例。但这带来了象征性的认知成本和相当字面的句法成本:然后必须依靠类型推断或类型注释来选择一个实例,并且有显式转换(在标准库中名为 OpgetOp)到并退出 Hask^op。

使用名称 fmapcontramap 可以降低这两项成本:读者无需在头脑中运行 Hindley-Milner 来决定选择哪个实例,而无需明确指定,编写者也无需给出明确的转换或键入注释以在不明确的情况下选择实例。

(实际上我在这里稍微改写了历史。真正的原因是因为语言设计者认为专用的Functor 会很有用,并且没有想象或没有看到需要对于更通用的Functor。人们后来发现它有时会很有用。但是通用Functor 类的经验表明这可能很乏味,而且针对最常见情况的专门类结果是毕竟,由于上述原因,非常适合。)

【讨论】:

    【解决方案2】:

    想象一下我们有类似以下的情况。

    class MoreAccurateFunctor c d f where
      fmap :: c a b -> d (f a) (f b)
    

    由于(->)Category 的一个实例(这是Hask),我们将拥有Functor ~ MoreAccurateFunctor (->) (->)

    现在,假设我们有 Dual (->)(->) 的双重类别(这将是 HaskOp,我们将有 Dual (->) a b ~ (b -> a)),我们会有那个Contravariant ~ MoreAccurateFunctor (Dual (->)) (->)

    我不知道这是否有帮助,但我的想法是指出FunctorContravariantMoreAccurateFunctor 的两个特化,而后者更接近于范畴论中函子的定义。

    【讨论】:

      【解决方案3】:

      在数学上,将逆变函子视为函子的一个独特的只是一种符号上的方便;逆变函子F : C -> D 总是可以定义为协变函子F' : C^{op} -> D,因此摆脱逆变函子的想法只会迫使您明确地谈论相反的类别。

      在 Haskell 中,Functor 类表示(假定的)类别 Hask 上的内函子。没有方便的方法来直接表示 HASKOP(或者至少,不能以帮助我们从该类别定义函子的形式),也没有定义exofunctor*,因此我们定义了 Contrafunctor 类,其 contramap 函数可以将 Hask 的箭头反转,可以说是“按需”。


      * “exofunctor”是一个真正的术语吗?我只是编造了一个不是内函子的函子。

      【讨论】:

      • @DanielWagner,在大多数情况下,我宁愿在Control.Category 中有newtype Op c a b = Op {getOp :: c b a}。我们是如何被 Data.Functor.Contravariant 中的 (->)-specialized 版本卡住的?我想更通用的版本可以称为Flip,但现在的情况有点奇怪。
      猜你喜欢
      • 2013-06-07
      • 2021-06-27
      • 1970-01-01
      • 2017-11-27
      • 1970-01-01
      • 2013-01-27
      • 1970-01-01
      • 2016-08-07
      • 2016-05-16
      相关资源
      最近更新 更多