相关的数据家族和重叠实例



我想要一个可以通过提供自定义实例来有效专业的'通用'映射数据结构,就像在类型家庭中的GHC手册部分一样。

{-# LANGUAGE FlexibleInstances    #-}
{-# LANGUAGE TypeFamilies         #-}
{-# LANGUAGE UndecidableInstances #-}
module MapKey where
import           Data.Map.Strict    (Map)
import qualified Data.Map.Strict    as Map
class MapKey k where
  data MMap k :: * -> *
instance {-# OVERLAPPING #-} MapKey () where
  newtype MMap () v = UnitMap (Maybe v)
instance {-# OVERLAPPABLE #-} Ord k => MapKey k where
  newtype MMap k v = OrdMap (Map k v)

可悲的是,这无效。GHC(8.2.1)抱怨:

    Conflicting family instance declarations:
      MMap () = UnitMap (Maybe v)
      MMap = OrdMap (Map k v)
   |
14 |   newtype MMap () v = UnitMap (Maybe v)
   |

是否有一些语言扩展可以允许这样做?否则,是否有另一种方法可以使用户轻松为Ord定义一个"默认"实例?

放弃重叠实例的一种解决方案是使用默认相关的注射类型族(相当嘴巴)。我还附加了一些默认MMap同义词的默认实现方法:

{-# LANGUAGE DefaultSignatures      #-}
{-# LANGUAGE TypeFamilies           #-}
{-# LANGUAGE TypeFamilyDependencies #-}
module MapKey where
import           Data.Map.Strict    (Map)
import qualified Data.Map.Strict    as Map
class MapKey k where
  type MMap k v = r | r -> k v
  type MMap k v = Map k v
  empty :: MMap k v
  default empty :: (MMap k v ~ Map k v) => MMap k v
  empty = Map.empty
  insert :: k -> v -> MMap k v -> MMap k v
  default insert :: (MMap k v ~ Map k v, Ord k) => k -> v -> MMap k v -> MMap k v
  insert = Map.insert
  lookupLE :: k -> MMap k v -> [(k, v)]
  default lookupLE :: (MMap k v ~ Map k v, Ord k) => k -> MMap k v -> [(k, v)]
  lookupLE k m =
    case Map.lookupLE k m of
      Nothing -> []
      Just e -> [e]
instance MapKey () where
  type MMap () v = Maybe v
  empty = Nothing
  insert _ v _ = Just v
  lookupLE _ m =
    case m of
      Nothing  -> []
      (Just v) -> [((), v)]

这意味着客户端代码仍然必须定义样板孤儿实例,例如

instance MapKey Int

我宁愿看到一种使用重叠实例的解决方案。

最新更新