Łatwe do zrobienia, jeśli masz przymusu rodzajów i rodzin typu. Po pierwsze, chciałbym powiedzieć, że wolą używać DataKinds
dla jasności
data HList ls where
HNil :: HList '[]
HCons :: x -> HList xs -> HList (x ': xs)
type family ConstrainAll (c :: * -> Constraint) (ls :: [*]) :: Constraint
type instance ConstrainAll c '[] =()
type instance ConstrainAll c (x ': xs) = (c x, ConstrainAll c xs)
showAll :: ConstrainAll Show xs => HList xs -> [String]
showAll HNil = []
showAll (HCons x xs) = (show x) : showAll xs
jeśli nie korzystać z nowych rozszerzeń to jest możliwe, ale o wiele brzydsze. Jedną opcją jest zdefiniowanie niestandardowych klas dla wszystkich, które uważam za brzydkie. Bardziej sprytny podejście byłoby fałszywe rodzaju przymusu
class Constrained tag aType where
isConstained :: tag aType
data HListT tag ls where
HNilT :: HListT tag()
HConsT :: x -> tag x -> HListT tag xs -> HListT tag (x,xs)
data Proxy (f :: * -> *) = Proxy
class ConstainedAll tag ls where
tagThem :: Proxy tag -> HList ls -> HListT tag ls
instance ConstainedAll tag() where
tagThem _ _ = HNilT
instance (ConstainedAll tag xs, Constrained tag x) => ConstainedAll tag (x,xs) where
tagThem p (HCons x xs) = HConsT x isConstained (tagThem p xs)
które można następnie wykorzystać jak
data Showable x where Showable :: Show x => Showable x
instance Show x => Constrained Showable x where isConstained = Showable
--inferred type showAll' :: HListT Showable xs -> [String]
showAll' HNilT = []
showAll' (HConsT x Showable xs) = (show x) : showAll' xs
--inferred type: showAll :: ConstainedAll Showable xs => HList xs -> [String]
showAll xs = showAll' (tagThem (Proxy :: Proxy Showable) xs)
example = showAll (HCons "hello" (HCons() HNil))
które powinny (miałaś testowane) pracować z dowolnym GHC z GADTs, MptC, elastyczne Konteksty/przypadkach i Kind Signatures (możesz łatwo pozbyć się ostatniego).
EDIT: W GHC 7.6+ należy użyć
type family ConstrainAll (c :: k -> Constraint) (ls :: [k]) :: Constraint
(k
zamiast *
) i włącz PolyKinds, ale to nie będzie działać z realizacją GHC 7.4 PolyKinds (stąd kod jednokształtny). W ten sam sposób definiowania
data HList f ls where
HNil :: HList f '[]
HCons :: !(f x) -> !(HList f xs) -> HList f (x ': xs)
pozwala uniknąć powielania kodu kiedy chcesz rzeczy jak leniwy vs ścisłych HLists lub gdy chcesz listę słowników, lub uniwersalne warianty wyższych typów kinded itd
Możesz dodać, że 'Ograniczenie' jest częścią pakietu' constraints', i musisz zaimportować 'Data.Constraint' dla rozwiązania' DataKinds'. Potrzebujesz również rozszerzenia 'ConstraintKinds'. :-) –
Łatwo ... Tak, to nie tak, że może być trudniejsze niż łączenie łańcuchów lub coś takiego, prawda? To łatwe. Easy to nazwa tego! Pewnie! To znaczy, patrzysz na to i całkowicie rozumiesz, dlaczego. Bułka z masłem!) Poważnie, dziękuję! –
Aby być uczciwym, rozwiązanie "Więzy" jest dość łatwe (w porównaniu do innych. Wszystko to dzięki temu, że DataKinds jest naprawdę użyteczny). Możesz zobaczyć bardziej ogólne podejście w tej odpowiedzi SO: http://stackoverflow.com/a/ 12995367/11797 Cały wątek jest całkiem interesujący i myślę, że może ci pomóc. –