容易,如果你有约束的种类和类型的家庭做。首先,让我说,我更喜欢使用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