Типовые ограничения для всех экземпляров семейства типов - PullRequest
9 голосов
/ 07 марта 2012

Полагаю, то, что я хочу, невозможно без 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 затрудняет понимание кода, как для меня.

Ответы [ 3 ]

7 голосов
/ 07 марта 2012

Используя виды ограничений 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 намного приятнее.

Я не совсем уверен, что вы ищете, но похоже, что вы просто хотите проще написать / понять сигнатуры ограничений, и в этом случае это будетработа.

2 голосов
/ 07 марта 2012

Вы можете написать это:

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
1 голос
/ 27 сентября 2013

Мне нравится пост Даниэля Вагнера, но вы не можете просто написать:

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
...