haskell - 仿函数泛化问题

标签 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 是什么?!我真的只是想让它消失。我可以使用 Identity通过让 f = 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

这很好。

现在,我可以立即识别一个问题,即对于 Functor 的给定 rt 参数,原始类定义允许 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 (如果是这种情况,我很乐意编译 head 来尝试这个)。
  2. 我可以进一步调整我的定义,以便 fr 确定 t 以及 ft 确定 r
  3. 执行上述操作后(如果不可能,则不执行)对类型推断有哪些潜在影响?
  4. 与原始类定义相比,除了增加打字量之外,还有其他不好的地方吗?
  5. 是否有其他方法仍然允许我定义 Kleisli 仿函数而不用 Identity 包装,同时比我提出的方法“更好”(更有用的结构、更好的类型推断等)。

很抱歉,最后几个问题有点模糊,我知道类型推断与通用性通常是一种权衡,但我只是在这种特殊情况下寻找一些关于它的想法。

(这个问题部分源于 this question 的答案)

最佳答案

你能得到的最接近的是

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

关于haskell - 仿函数泛化问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32695316/

相关文章:

haskell - profunctors和箭头有什么关系?

haskell - 你将如何在 Haskell 中(重新)实现迭代?

haskell - 组合学:圣彼得博弈算法

f# - 如何在 F# 中为 OCaml 中的仿函数编写代码?

haskell - 如何将延续单子(monad)分解为左右伴随?

haskell - uncurry 和 fanin 在范畴论中是如何关联的?

performance - 为什么该程序的 F# 版本比 Haskell 版本快 6 倍?

list - Haskell - 如何计算嵌套列表中的元素

C++ std::for_each() 函数参数类型是什么?

c++ - C++ 中的 Reader 仿函数