2012-03-07 16 views
9

Przypuszczam, że to, czego chcę, jest niemożliwe bez szablonu Haskella, ale mimo to zapytam.Ograniczenia typu we wszystkich instancjach rodzinnych typów

Mam interfejs dla typów jak Data.Set i 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 
    ... 

I mam rodzinę typu, który wybiera optymalny zestaw realizacji:

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

Czy istnieje sposób, aby zagwarantować, że EfficientSet instancji będzie zawsze SetLike i że Elem (EfficientSet a) jest a?

Bez tej gwarancji wszystkie podpisy funkcja będzie tak:

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

Aby pisać za każdym razem SetLike LocationSet jest dość znośny, ale Elem LocationSet ~ Location sprawia zrozumienie kodu tylko mocniej, jak dla mnie.

Odpowiedz

7

Korzystanie GHC 7.4 w rodzaju przymusu można mieć coś podobnego

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

Można (z odpowiednimi rozszerzeniami) dostać ograniczeń jak to we wcześniejszych wersjach GHC

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

Ale nowa deklaracja stylu type jest o wiele ładniejsza.

Nie jestem do końca pewien, czego szukasz, ale brzmi to tak, jakbyś po prostu chciał łatwiej pisać/rozumieć podpisy ograniczające, w takim przypadku to zadziała.

+0

Naprawdę? Deklaracja synonimów typu "type" może definiować nie tylko synonim typu, ale synonim ograniczenia typu? Ciekawy. Czy to działa również z niejawnymi ograniczeniami typu parametru? –

+0

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

2

można napisać to:

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

Jeśli skojarzyć rodzinę Elem typu z klasą SetLike, prawdopodobnie nawet nie potrzebują SetLike nadrzędnej ograniczenia:

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

I jak Daniel Post Wagnera, ale nie możesz po prostu napisać:

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

Trzeba napisać:

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

Ale to można przezwyciężyć synonim więzów:

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 
Powiązane problemy