【问题标题】:What's the relationship between profunctors and arrows?profunctors和箭头之间有什么关系?
【发布时间】:2016-11-05 06:50:18
【问题描述】:

显然,每个Arrow 都是Strong 的代言人。实际上^>>>>^ 对应于lmaprmap。而first'second'firstsecond 相同。同样每个ArrowChoice 也是Choice

与箭头相比,profunctor 缺乏的是组合它们的能力。如果我们添加合成,我们会得到一个箭头吗?换句话说,如果一个(强)profunctor 也是一个category,它已经是一个箭头了吗?如果没有,缺少什么?

【问题讨论】:

标签: haskell functor category-theory arrows profunctor


【解决方案1】:

与箭头相比,profunctor 缺乏的是组合它们的能力。如果我们添加合成,我们会得到一个箭头吗?

类群

这正是“Notions of Computation as Monoids”的第 6 节中解决的问题,它解开了(相当密集的)“Categorical semantics for arrows”的结果。 “概念”是一篇很棒的论文,因为虽然它深入探讨了范畴论,但它 (1) 并没有假设读者对抽象代数有粗略的了解,并且 (2) 用 Haskell 代码说明了大多数诱发偏头痛的数学。我们可以在这里简要总结论文的第 6 部分:

说我们有

class Profunctor p where
  dimap :: (contra' -> contra) -> (co -> co') -> p contra co -> p contra' co'

您在 Haskell 中对 profunctor 的沼泽标准、正负除法编码。现在这个数据类型,

data (⊗) f g contra co = forall x. (f contra x) ⊗ (g x co)

正如在Data.Profunctor.Composition 中实现的那样,其作用类似于profunctor 的组合。例如,我们可以证明一个合法的实例Profunctor

instance (Profunctor f, Profunctor g) => Profunctor (f ⊗ g) where
  dimap contra co (f ⊗ g) = (dimap contra id f) ⊗ (dimap id co g)

出于时间和空间的原因,我们将举手证明它是合法的。

好的。现在有趣的部分。说我们这个类型类:

class Profunctor p => ProfunctorMonoid p where
  e :: (a -> b) -> p a b
  m :: (p ⊗ p) a b -> p a b

这是一种在 Haskell 中编码 profunctor monoids 概念的方式。具体来说,这是幺半群Pro 中的幺半群,它是函子类别[C^op x C, Set] 的幺半群结构, 作为张量,Hom 作为其单位。所以这里有很多超具体的数学术语需要解压,但你应该阅读这篇论文。

然后我们看到ProfunctorMonoidArrow 同构......几乎。

instance ProfunctorMonoid p => Category p where
  id = dimap id id
  (.) pbc pab = m (pab ⊗ pbc)

instance ProfunctorMonoid p => Arrow p where
  arr = e
  first = undefined

instance Arrow p => Profunctor p where
  lmap = (^>>)
  rmap = (>>^)

instance Arrow p => ProfunctorMonoid p where
  e = arr
  m (pax ⊗ pxb) = pax >> pxb

当然,我们在这里忽略了类型类定律,但正如论文所示,它们确实非常有效。

现在我说几乎是因为我们无法实现first。我们真正所做的是证明了ProfunctorMonoidpre-arrows 之间的同构。论文称Arrow 没有first 一个pre-arrow。然后它继续表明

class Profunctor p => StrongProfunctor p where
  first :: p x y -> p (x, z) (y, z)

class StrongProfunctor p => StrongProfunctorMonoid p where
  e :: (a -> b) -> p a b
  m :: (p ⊗ p) a b -> p a b

对于Arrow 的所需同构是必要且充分的。 “强”这个词来自范畴论中的一个特定概念,这篇论文以比我所能想到的更好的文字和更丰富的细节来描述。

总结一下:

  • profunctor 类别中的幺半群是前箭头,反之亦然。 (该论文的先前版本使用术语“弱箭头”而不是预箭头,我想这也可以。)

  • 强仿函数类别中的幺半群是箭头,反之亦然。

  • 由于 monad 是内函子范畴中的幺半群,我们可以将其与 SAT 类比 Functor : Profunctor :: Monad : Arrow。这是计算概念作为幺半群论文的真正主旨。

  • Monoids 和 monoidal 类别是随处可见的温和海洋生物,有些学生会在没有学习过 monoids 的情况下接受计算机科学或软件工程教育,这是一种耻辱。

  • 范畴论很有趣。

  • Haskell 很有趣。

【讨论】:

    【解决方案2】:

    @haoformayor 的回答(和参考论文)是对基本类别理论的一个很好的洞察——幺半群类别相当漂亮! - 但我认为一些代码向您展示了如何将 Arrow 转换为 Strong Category,反之亦然,因为它们出现在各自的库中可能会成为一个有用的附录。

    import Control.Arrow
    import Control.Category
    import Data.Profunctor
    import Data.Profunctor.Strong
    import Prelude hiding (id, (.))
    

    一种方式...

    newtype WrapP p a b = WrapP { unwrapP :: p a b }
    
    instance Category p => Category (WrapP p) where
        id = WrapP id
        WrapP p . WrapP q = WrapP (p . q)
    
    instance (Category p, Strong p) => Arrow (WrapP p) where
        first = WrapP . first' . unwrapP
        second = WrapP . second' . unwrapP
    
        -- NB. the first usage of id comes from (->)'s Category instance (id :: a -> a)
        -- but the second uses p's instance (id :: p a a)
        arr f = WrapP $ dimap f id id
    

    ...还有其他...

    newtype WrapA p a b = WrapA { unwrapA :: p a b }
    
    instance Arrow p => Profunctor (WrapA p) where
        dimap f g p = WrapA $ arr f >>> unwrapA p >>> arr g
    
    instance Arrow p => Strong (WrapA p) where
        first' = WrapA . first . unwrapA
        second' = WrapA . second . unwrapA
    

    【讨论】:

    • 有了dimap f id id 的那篇文章,你让我大开眼界。最后我意识到StrongCategory 对于Arrow 来说已经足够了! :) 谢谢
    • dimap id f id,是的。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-10-30
    • 2015-01-02
    • 2012-07-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-04-08
    相关资源
    最近更新 更多