2012-03-07 12 views
9

Suppongo che ciò che voglio sia impossibile senza Template Haskell ma lo chiederò comunque.Vincoli di tipo su tutte le istanze di tipo famiglia

ho un'interfaccia per i tipi come Data.Set e 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 
    ... 

E ho una famiglia tipo che sceglie implementazione set ottimale:

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

C'è un modo per garantire che EfficientSet casi sarà sempre SetLike e che Elem (EfficientSet a) è a?

Senza questa garanzia tutte le firme funzione sarà simile a questo:

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

Per scrivere ogni volta SetLike LocationSet è un po 'tollerabile, ma Elem LocationSet ~ Location rende il codice più difficile la comprensione solo, per quanto mi riguarda.

risposta

7

Utilizzando GHC 7.4 di tipi di vincoli si potrebbe avere qualcosa di simile

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

È possibile (con estensioni appropriate) ottenere vincoli di questo tipo nelle versioni precedenti di GHC

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

Ma, il nuovo la dichiarazione di stile type è molto più bella.

Non sono esattamente sicuro di quello che stai cercando, ma sembra che tu voglia semplicemente scrivere/capire le firme dei vincoli, nel qual caso funzionerà.

+0

Davvero? Una dichiarazione di sinonimo 'type' può definire non solo un sinonimo di tipo, ma un sinonimo di tipo vincolo? Interessante. Funziona anche con vincoli di tipo di parametro implicito? –

+0

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

2

È possibile scrivere questo:

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

Se si associa la famiglia Elem tipo con la classe SetLike, probabilmente non è nemmeno necessario il vincolo SetLike 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

mi piace Daniel Il post di Wagner, ma non si può semplicemente scrivere:

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

dovete scrivere:

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

Ma questo può essere superato con un sinonimo vincolo:

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 
Problemi correlati