一个更通用的Functor类

时间:2015-09-22 04:28:16

标签: haskell typeclass

这个问题可能看起来有些愚蠢,但我先问一下然后解释背后的理由。

让我们说我们通过以下方式重新定义Functor

{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE FlexibleInstances #-}

class Functor a where
  generic_fmap :: a

instance Functor ((a -> b) -> Maybe a -> Maybe b) where
  generic_fmap f (Just x) = Just (f x)
  generic_fmap _ Nothing = Nothing

instance Functor ((a -> b) -> [a] -> [b]) where
  generic_fmap = map

-- etc with more instances    

然后,我已经考虑过两种方法来定义fmap

(1):

fmap :: (Functor ((a -> b) -> f a -> f b)) => (a -> b) -> f a -> f b
fmap = generic_fmap

或(2)(需要不可判定的实例)(已编辑):

class Functor f a b where
  fmap :: (a -> b) -> f a -> f b

instance (GenericFunctor ((a -> b) -> f a -> f b)) => Functor f a b where
  fmap = generic_fmap

除了增加的打字和丑陋之外,还有什么我们失去了以这两种方式定义fmap

我问的原因是我发现标准Functor类比数学定义更具体,所以许多其他适合作为仿函数的东西不能成为仿函数哈斯克尔。我的想法是定义一个非常通用的Functor类(尽管可能不像上面那样通用)。但是,通过使它过于通用,你会失去类型推断。因此,用户可以决定使用不同版本的fmap,具体取决于它们是否需要通用性或类型推断。与用户如何在前奏中.(仅适用于标准函数)或.中的Control.Category(适用于所有类别)之间进行选择非常相似。

我知道还有很多向后兼容性问题,但我的第一个问题是,我的定义是否与使用用户相同(不要担心那些想要定义实例的人)此时此刻)。

2 个答案:

答案 0 :(得分:4)

据我们所知,即使使用UndecidableInstances,您的定义也无法在当前的GHC中发挥作用。

问题是你需要一个假设的扩展" RankNConstraints"这将允许您在上一个实例声明中提及ab,尽管它们不在其中,例如如

instance (forall a b. GenericFunctor ((a -> b) -> f a -> f b)) => Functor f where

我已经想过,为了这个以及许多其他目的,这个扩展程序会很棒(例如Stackoverflow的答案会继续出现在看似相关的地方)。还有很多其他人,至少2000年SPJ和Ralph Hinze建议它in a paper

不幸的是,我最近从old GHC ticket那里了解到,如何明智地实施它是因为它会对类型推断造成严重破坏。

答案 1 :(得分:2)

我认为这里更大的问题是Functor不仅仅是map,还有一些与之相关的法律。我不知道你如何能为你提出的GenericFunctor表达法律。

例如,id中的(.)Category定义了身份和组合的含义 - 现在您可以为一对GenericFunctor定义Categories