Co naprawdę chcesz to
data HKList :: (k -> *) -> [k] -> * where
Nil :: HKList f '[]
(:*) :: f x -> HKList f xs -> HKList f (x ': xs)
które można wykorzystać zarówno jako zwykły listy heterogenicznej
type HList = HKList Identity
Albo z dodatkowymi informacjami o pewnej stałej typu e
dołączonym do każdej wartości (lub inny interesujący funktorzy)
HKList ((,) e)
Lub z dodatkowymi informacjami na ujęte w słowniku
data Has c a where
Has :: c a => a -> Has c a
type ConstrainedList c = HKList (Has c)
Albo przechowuje wykazy tylko przechwyconych ograniczeń
data Dict1 :: (k -> Constraint) -> k -> * where
Dict1 :: c k => Dict1 c k
które można wykorzystać do zdefiniowania pojęcia wszystkich z listy typów spełniających ograniczenie
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
Lub cokolwiek innego, co możesz zrobić z pewnym rodzajem k -> *
Możesz fre ely konwersji pomiędzy pracę z All c xs => HList xs
i 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
Pisałem to kilka razy, zanim na różne projekty, ale nie wiedziałem, że był w bibliotece nigdzie aż Kosmikus pointed out that it's in generics-sop
.
Ja też nie widziałem. Pracowałem nad czymś takim jakiś czas temu, ale nigdy nie miałem tego w formie, w której czułem, że powinno się to załadować. [Możesz także natknąć się na dziwne zakątki tego typu systemu, odkrywając to] (https://github.com/roboguy13/existentialist/blob/master/src/Data/Existentialist.hs#L67). –