在a previous answer中,Petr Pudlak定义了CFunctor
类,用于除 Hask 到 Hask 之外的算子。使用类型系列重写它,它看起来像
class CFunctor f where
type Dom f :: * -> * -> * -- domain category
type Cod f :: * -> * -> * -- codomain category
cmap :: Dom f a b -> Cod f (f a) (f b) -- map morphisms across categories
具有看起来像的例子,例如
instance CFunctor Maybe where
type Dom Maybe = (->) -- domain is Hask
type Cod Maybe = (->) -- codomain is also Hask
cmap f = \m -> case m of
Nothing -> Nothing
Just x -> Just (f x)
在类别理论中,每当 F:C - > D 是一个仿函数, G:D - > E 是仿函数,然后组合 GF:C - > E 也是一个仿函数。
我想在Haskell中表达这一点。由于我无法编写instance CFunctor (f . g)
,因此我引入了一个包装类:
newtype Wrap g f a = Wrap { unWrap :: g (f a) }
在编写CFunctor
实例时,我得到了
instance (CFunctor f, CFunctor g, Cod f ~ Dom g) => CFunctor (Wrap g f) where
type Dom (Wrap g f) = Dom f
type Cod (Wrap g f) = Cod g
cmap = undefined
但我无法弄清楚cmap
的实现应该是什么。有什么建议吗?
PS 所有这一切的最终原因是还引入了一个包含方法Adjunction
和unit
的类counit
,然后从附件中自动派生monad实例。但首先,我需要向编译器显示两个仿函数的组合也是一个仿函数。
我知道我可以在cmap.cmap
类型的对象上使用g (f a)
并且这样可行,但它看起来有点像作弊 - 当然,仿函数只是一个仿函数,编译器不应该知道它实际上是其他两个仿函数的组成吗?
答案 0 :(得分:6)
给定仿函数F : C → D
和G : D → E
,仿函数合成G ∘ F : C → E
是类别C
和E
之间的对象映射,这样{{1}和morphisms之间的映射,使(G ∘ F)(X) = G(F(X))
。
这表明您的(G ∘ F)(f) = G(F(f))
实例应定义如下:
CFunctor
但是,撰写instance (CFunctor f, CFunctor g, Cod f ~ Dom g) => CFunctor (Wrap g f) where
type Dom (Wrap g f) = Dom f
type Cod (Wrap g f) = Cod g
cmap f = cmap (cmap f)
两次会为您提供cmap
,而Dom f a b -> Cod g (g (f a)) (g (f b))
在此实例中的类型为cmap
。
我们可以从Dom f a b -> Cod g (Wrap g f a) (Wrap g f b)
到g (f a)
,反之亦然,但由于实例声明不对Wrap g f
的结构做出任何假设,我们运气不佳。 / p>
由于我们知道functor是类别之间的映射,我们可以使用Cod g
是Cod g
的事实(在Haskell方面,这需要Category
约束),这给出了我们很少有与之合作的行动:
Category (Cod g)
但是,这需要一个方便的提升操作员cmap f = lift? unWrap >>> cmap (cmap f) >>> lift? Wrap
,它将功能从lift?
类别提升到Hask
类别。将Cod g
写为Cod g
,(~>)
的类型必须为:
lift?
现在,这个提升算子至少有两种选择:
lift? :: (a -> b) -> (a ~> b)
lift? unWrap :: Wrap g f a ~> g (f a)
cmap (cmap f) :: g (f a) ~> g (f b)
lift? Wrap :: g (f b) ~> Wrap g f b
lift? unWrap >>> cmap (cmap f) >>> lift? Wrap :: Wrap g f a ~> Wrap g f b
展开到Category (Cod g)
,在这种情况下,提升运算符变为Arrow (Cod g)
,arr
和Wrap
在语义上unWrap
的事实,在这种情况下使用id
是有道理的。