【发布时间】:2015-09-21 21:14:02
【问题描述】:
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 实例,如下所示(没有丑陋的 Identity 包装器):
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 和 t 参数到 Functor,原始类定义允许 f 有多个选项,而根据我的定义,@987654341 @ 和 t 确定 f。这是一个严重的问题,好像我定义说:
fmap :: (a -> b) -> (Maybe a -> Maybe b)
我无法定义:
fmap :: (a -> b) -> ([a] -> [b])
在这两种情况下,r = (->) 和 t = (->)。所以目前我的Functor 甚至没有替换原来的 Prelude 版本。
所以我现在有一些问题:
- 我可以调整我的定义,使
r和t不能确定f(与原始版本一样)吗?或者这是否需要Injective Type Families(如果是这种情况,我很乐意编译头部来尝试这个)。 - 我能否进一步调整我的定义,使
f和r确定t以及f和t确定r? - 执行上述操作后(如果不可能,则不执行)对类型推断有哪些潜在影响?
- 与原来的相比,我的类定义是否还有其他不好的地方,比如增加打字?
- 是否有任何替代方法仍然允许我定义 Kleisli 函子而不用 Identity 包装,同时比我提出的“更好”(更有用的结构、更好的类型推断等)。
很抱歉,最后几个问题有点含糊,我知道类型推断与一般性通常是一种权衡,但我只是在这个特殊情况下寻找一些想法。
(这个问题部分来自对this question的回答)
【问题讨论】:
标签: haskell functor category-theory