在所有类型族实例上键入约束

时间:2012-03-07 09:35:05

标签: haskell types type-families

我想如果没有Template Haskell,我想要的是不可能的,但无论如何我都会问。

我有Data.SetData.IntSet类型的界面:

type family Elem s :: *
class SetLike s where
  insert :: Elem s -> s -> s
  member :: Elem s -> s -> Bool
  ...

type instance Elem (Set a) = a
instance Ord a => SetLike (Set a) where
  ...

我有一个选择最佳集合实现的类型系列:

type family EfficientSet elem :: *
type instance EfficientSet Int = IntSet
type instance EfficientSet String = Set String -- or another implementation

有没有办法保证EfficientSet个实例始终为SetLikeElem (EfficientSet a)a

如果没有这个保证,所有功能签名都是这样的:

type LocationSet = EfficientSet Location
f :: (SetLike LocationSet, Elem LocationSet ~ Location) => ...

每次SetLike LocationSet都可以容忍,但Elem LocationSet ~ Location使代码理解变得更难,就像我一样。

3 个答案:

答案 0 :(得分:7)

使用GHC 7.4的约束种类,你可以使用

type EfficientSetLike a = (SetLike (EfficientSet a),Elem (EfficientSet a) ~ a)

您可以(使用适当的扩展名)在早期版本的GHC中获得这样的约束

class (SetLike (EfficientSet a),Elem (EfficientSet a) ~ a) => EfficientSetLike a 
instance (SetLike (EfficientSet a),Elem (EfficientSet a) ~ a) => EfficientSetLike a 

但是,新样式type声明要好得多。

我不确定你在寻找什么,但听起来你只是想更容易编写/理解约束签名,在这种情况下,这将有效。

答案 1 :(得分:2)

你可以这样写:

class (SetLike (EfficientSet a), Elem (EfficientSet a) ~ a) =>
      HasEfficientSet a where
    type EfficientSet a

如果您将Elem类型系列与SetLike类相关联,则可能甚至不需要SetLike超类约束:

class SetLike s where
    type Elem s
    insert :: Elem s -> s -> s
    member :: Elem s -> s -> Bool

class Elem (EfficientSet a) ~ a => HasEfficientSet a where
    type EfficientSet a

答案 2 :(得分:1)

我喜欢Daniel Wagner的帖子,但你不能只写:

test :: (HasEfficientSet a) => EfficientSet a
test = empty

你必须写:

test :: (HasEfficientSet a, SetLike (EfficientSet a)) => EfficientSet a
test = empty

但是这可以通过约束同义词来克服:

class SetLike s where 
    type Elem s :: *
    empty :: s
    insert :: Elem s -> s -> s 
    member :: Elem s -> s -> Bool 

class (Elem (EfficientSet a) ~ a) => HasEfficientSet' a where
    type EfficientSet a :: *

type HasEfficientSet a = (HasEfficientSet' a, SetLike (EfficientSet a))


newtype UnitSet = UnitSet Bool
    deriving (Show, Eq, Ord)

instance SetLike UnitSet where
    type Elem UnitSet = ()
    empty = UnitSet False 
    insert () _ = UnitSet True
    member () u = UnitSet True == u

instance HasEfficientSet' () where
    type EfficientSet () = UnitSet


test :: (HasEfficientSet a) => EfficientSet a
test = empty

test1 :: EfficientSet ()
test1 = empty

test2 :: EfficientSet ()
test2 = test

test3 :: UnitSet
test3 = empty

test4 :: UnitSet
test4 = test