容易,如果你有約束的種類和類型的家庭做。首先,讓我說,我更喜歡使用DataKinds
爲清楚起見
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
如果不使用新的擴展是可能的,但更噁心。一種選擇是定義所有東西的自定義類別
class ShowAll ls where
showAll :: HList ls -> [Show]
instance ShowAll() where
showAll _ = []
instance (ShowAll xs, Show x) => ShowAll (x,xs)
showAll (HCons x xs) = (show x) : (showAll xs)
我覺得這很醜陋。一個更聰明的方法是假的約束種
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)
然後你就可以像
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))
應(還沒有測試)工作與任何GHC使用與GADTs,MPTC,靈活的上下文/情況下,和親切簽名(你可以輕鬆擺脫最後一個)。
編輯:GHC 7.6+,你應該使用
type family ConstrainAll (c :: k -> Constraint) (ls :: [k]) :: Constraint
(k
而不是*
)並打開PolyKinds,但這不會與GHC 7.4實施PolyKinds的(因此單態代碼工作)。以同樣的方式,確定
data HList f ls where
HNil :: HList f '[]
HCons :: !(f x) -> !(HList f xs) -> HList f (x ': xs)
可以讓你避免代碼重複,當你想要的東西就像一個懶惰VS嚴格HLists或當你想詞典列表,或更高kinded類型的普遍變形等
你可能想要補充一點,'Constraint'是constraints包的一部分,你必須爲'DataKinds'解決方案導入'Data.Constraint'。你還需要'ConstraintKinds'擴展。 :-) – 2013-04-25 09:37:36
簡單...是的,它不像它可能比連接字符串或其他東西更難,對嗎?這很容易。簡單就是它的名字!當然!我的意思是,你看着它,你完全明白爲什麼。小菜一碟! )雖然真的,謝謝! – 2013-04-25 09:58:25
公平地說,'Constraint'解決方案非常簡單(與其他所有方法相比,由於DataKinds非常有用)。您可以在此答案中看到更一般的方法:http://stackoverflow.com/a/ 12995367/11797整個線程實際上很有趣,我認爲它可以幫助你。 – 2013-04-25 11:12:14