我想如果没有Template Haskell,我想要的是不可能的,但无论如何我都会问。
我有Data.Set
和Data.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
个实例始终为SetLike
且Elem (EfficientSet a)
为a
?
如果没有这个保证,所有功能签名都是这样的:
type LocationSet = EfficientSet Location
f :: (SetLike LocationSet, Elem LocationSet ~ Location) => ...
每次SetLike LocationSet
都可以容忍,但Elem LocationSet ~ Location
使代码理解变得更难,就像我一样。
答案 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