【发布时间】:2012-12-10 12:00:16
【问题描述】:
在a previous answer 中,Petr Pudlak 为 Hask 到 Hask 以外的函子定义了 CFunctor 类。使用类型族重新编写它,它看起来像
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 实例。但首先,我需要向编译器表明,两个仿函数的组合也是一个仿函数。
我知道我可以在 g (f a) 类型的对象上使用 cmap.cmap 并且这会起作用,但这看起来有点像作弊 - 肯定函子只是函子,编译器不应该有知道它实际上是另外两个函子的组合吗?
【问题讨论】:
-
对于 Hask 上的 endofunctors,
DeriveFunctor扩展肯定会自动处理(和许多其他情况)。但是,如果您必须手动实现它,我不明白为什么您会期望比通过在每个函数上组合映射来映射组合函子更简单的方法? -
基本上,
cmap f = cmap (cmap f)是函子组合的定义,那么为什么要以任何方式作弊呢? -
@CAMcCann 我很乐意将
cmap = cmap . cmap写为实现,但这对于类型构造函数Wrap g f是不正确的(特别是,它需要Dom f a b到Cod g (g (f a)) (g (f b))而不是比Cod g (Wrap g f a) (Wrap g f b)。如上所述,我对Hask 上的内函子以外的情况其他特别感兴趣。 -
@DanielFischer 因为
g (f a)不只是两个函子的组合,它本身也是一个函子,所以我想我应该可以在它上面使用cmap(有点类似于如何使用 monad 转换器时,您不必到处写lift . lift . lift,如果您可以告诉编译器如何自动提升某些功能 - 在这里我想告诉编译器如何使用 a 跨两个类别映射态射cmap) 的单个应用程序。 -
我的意思是在
cmap的定义中使用Wrap f g。但是,看着它,我不明白如何为一般g做这件事;只有Cod g = (->)才明显。
标签: haskell functor category-theory