2012-03-07 2 views
9

Je suppose que ce que je veux est impossible sans Template Haskell mais je demanderai quand même.Contraintes de type sur toutes les instances de type famille

je une interface pour les types comme Data.Set et 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 
    ... 

Et j'ai une famille de type qui choisit la mise en œuvre de jeu optimal:

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

est-il un moyen de garantir que les EfficientSet instances sera toujours SetLike et que Elem (EfficientSet a) est a?

Sans cette garantie sera comme toutes les signatures de fonction ceci:

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

Pour écrire chaque fois SetLike LocationSet est un peu tolérable, mais Elem LocationSet ~ Location rend la compréhension du code que plus difficile, comme pour moi.

Répondre

7

aide GHC 7.4 de les types que vous pourriez avoir quelque chose comme

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

Vous pouvez (avec des extensions appropriées) obtenir des contraintes comme dans les versions antérieures de GHC

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

Mais, la nouvelle style déclaration type est beaucoup plus agréable.

Je ne sais pas exactement ce que vous cherchez, mais il semble que vous vouliez simplement écrire/comprendre des signatures de contraintes, auquel cas cela fonctionnera.

+0

Vraiment? Une déclaration de synonyme 'type' peut définir non seulement un synonyme de type, mais un synonyme de contrainte de type? Intéressant. Est-ce que cela fonctionne aussi avec des contraintes implicites de type de paramètre? –

+0

@JeffBurdges Yep: http://www.haskell.org/ghc/docs/7.4.1/html/users_guide/constraint-kind.html –

2

Vous pouvez écrire ceci:

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

Si vous associez la famille de type Elem avec la classe SetLike, vous auriez probablement même pas besoin de la SetLike contrainte superclasse:

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

J'aime Daniel Le message de Wagner, mais vous ne pouvez pas écrire:

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

Vous devez écrire:

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

Mais cela peut être surmonté par un synonyme de contrainte:

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 
Questions connexes