如果我们将类别的理解限制为 Haskell 中常见的
Category
类:
class Category c where
id :: c x x
(>>>) :: c x y -> c y z -> c x z
那么我们假设
Arrow
是 Category
,它还可以:
class Category c => Arrow c where
(***) :: c x y -> c x' y' -> c (x,x') (y,y')
(&&&) :: c x y -> c x y' -> c x (y,y')
我们很容易得出:
first :: c x y -> c (x,z) (y,z)
first a = a *** id
second :: c x y -> c (z,x) (z,y)
second a = id *** a
或者我们可以从
(***)
和 first
导出 second
:
a1 *** a2 = first a1 >>> second a2
我们还可以推导出:
dup :: c x (x,x)
dup = id &&& id
或者我们可以根据
(&&&)
和 dup
推导出 (***)
:
a1 &&& a2 = dup >>> (a1 *** a2)
我的观点是什么,我的问题是什么?是这个:
没有
Arrow
的 arr
是什么?它看起来非常连贯且有用。是否存在任何不涉及 arr
并且在这里保持完整的箭头定律(除了类别定律)?这在范畴论中意味着什么?
这个问题我基本上是从reddit上偷来的,但对其进行了概括和阐述: http://www.reddit.com/r/haskell/comments/2e0ane/category_with_fanout_and_split_but_not_an_arrow/
正如
Arrow
是一个包含产品的类别一样,Arrow
没有 arr
也是一个包含产品的类别(因此类别法则始终成立)。
arr
是从Hask类别到c
类别的函子。下面显示的代码表明了这一点。 arr
提供了一种将普通函数(Hask 中的态射)提升到实例化 c
类别的方法。这有点像 fmap
(从 Hask 到 Hask 的函子),但更通用。与此相关,一些箭头定律here描述了函子定律(尽管也有乘积定律)。
因此,通过省略
arr
,您将失去提升正常功能的功能,或者从另一个角度来看,无需实现它。然而,所有其他特征都是相同的。
{-# LANGUAGE TypeOperators, RankNTypes #-}
-- | Functor arrow
type (:->) c d = forall a b. c a b -> d a b
-- | Hask category; types are objects, functions are morphisms.
type Hask = (->)
arr :: Arrow c => Hask :-> c
arr = Control.Arrow.arr