问题Generalising Functor

时间:2015-09-21 12:32:05

标签: haskell functor category-theory

Functor in Control.Categorical.Functor具有以下定义:

class (Category r, Category t) => Functor f r t | f r -> t, f t -> r where
  fmap :: r a b -> t (f a) (f b)

但是我想说我想要一个从普通函数到Kleisli箭头的仿函数(这可能是一个愚蠢的例子)。

我想要一个这样的类型:

fmap :: (Monad m) => (a -> b) -> Kleisli m a b

我可以让r = (->)t = Kleisli m获取:

fmap :: (Monad m) => (a -> b) -> Kleisli m (f a) (f b)

但是,那是什么f?!我真的只是希望它消失。我可以通过f = Identity来使用Identity仿函数,但后来我得到了:

fmap :: (Monad m) => (a -> b) -> Kleisli m (Identity a) (Identity b)

这需要一些杂乱的解包。

然后我想到像这样定义Functor:

class (Category r, Category t) => Functor r t where
  type family F r t x :: *
  fmap :: r a b -> t (F r t a) (F r t b)

这允许我为Kleisli定义一个Functor实例,如下所示(没有丑陋的身份包装器):

instance (Monad m) => Functor (->) (Kleisli m) where
  type F (->) (Kleisli m) a = a
  fmap f = Kleisli (return . f)

在此之后,我很确定我在:

fmap :: (Monad m) => (a -> b) -> Kleisli m a b

哪个好。

现在,我可以立即识别出一个问题,即,对于r的给定tFunctor参数,原始类定义允许f的多个选项,而根据我的定义,rt决定f。这是一个严重的问题,好像我定义说:

fmap :: (a -> b) -> (Maybe a -> Maybe b)

我无法定义:

fmap :: (a -> b) -> ([a] -> [b])

与两种情况一样,r = (->)t = (->)。所以目前我的Functor甚至没有取代原来的Prelude版本。

所以我现在有一些问题:

  1. 我可以调整我的定义,因此rt不会确定f(与原始版本一样)吗?或者这需要Injective Type Families(如果是这种情况,我很乐意编译头来尝试这个)。
  2. 我是否可以进一步调整我的定义,以便fr确定t以及ft确定r
  3. 完成上述操作后(或者如果不可能),对类型推断的潜在影响是什么?
  4. 与原版相比,我的班级定义是否还有其他不好的事情,除了增加打字等内容?
  5. 是否有任何替代方法仍然允许我定义Kleisli仿函数而不包含Identity,同时“更好”我所建议的(更有用的结构,更好的类型推断等)。
  6. 对不起,最后几个问题有点模糊,我知道类型推断与普遍性通常是一种权衡,但我只是在这个特殊情况下寻找一些想法。

    (这个问题部分来自对this question

    的回答

1 个答案:

答案 0 :(得分:3)

你能得到的最接近的是

class (Category r, Category t) => Functor
          (f :: *) (r :: *->*->*) (t :: *->*->*) where
  type F f x :: *
  fmap :: Tagged f ( r a b -> t (F f a) (F f b) )

instance Functor [()] (->) (->) where
  type F [()] x = [x]
  fmap = Tagged map

instance (Monad m) => Functor (Kleisli m () ()) (->) (Kleisli m) where
  type F (Kleisli m () ()) x = x
  fmap = Tagged $ \f -> Kleisli $ return . f