What you really want is
data HKList :: (k -> *) -> [k] -> * where
Nil :: HKList f '[]
(:*) :: f x -> HKList f xs -> HKList f (x ': xs)
Which you can use either as an ordinary heterogeneous list
type HList = HKList Identity
Or with extra information of some constant type e
attached to each value (or other interesting functors)
HKList ((,) e)
Or with extra information captured in a dictionary
data Has c a where
Has :: c a => a -> Has c a
type ConstrainedList c = HKList (Has c)
Or keep lists of only captured constraints
data Dict1 :: (k -> Constraint) -> k -> * where
Dict1 :: c k => Dict1 c k
Which you can use to define the idea of all of a list of types satisfying a constraint
class All c xs where
dicts :: HKList (Dict1 c) xs
instance All c '[] where
dicts = Nil
instance (All c xs, c x) => All c (x ': xs) where
dicts = Dict1 :* dicts
Or anything else you can do with a kind k -> *
You can freely convert between working with All c xs => HList xs
and HKList (Has c) xs
zipHKList :: (forall k. f k -> g k -> h k) -> HKList f xs -> HKList g xs -> HKList h xs
zipHKList _ Nil Nil = Nil
zipHKList f (x :* xs) (y :* ys) = f x y :* zipHKList f xs ys
allToHas :: All c xs => HKList Identity xs -> HKList (Has c) xs
allToHas xs = zipHKList f dicts xs
where
f :: Dict1 c k -> Identity k -> Has c k
f Dict1 (Identity x) = Has x
hasToAll :: HKList (Has c) xs -> Dict (All c xs)
hasToAll Nil = Dict
hasToAll (Has x :* xs) =
case hasToAll xs of
Dict -> Dict
full code
I've written this a few times before for various projects, but I didn't know it was in a library anywhere until Kosmikus pointed out that it's in generics-sop
.