Reputation: 21811
This is a followup to a previous question: Type-level Map with DataKinds, starting with from the two answers it received.
My goal is to take a HList
of arbitrary types and turn it into a list of related/derived types
type family TypeMap (a :: * -> *) (xs :: [*]) :: [*]
type instance TypeMap t '[] = '[]
type instance TypeMap t (x ': xs) = t x ': TypeMap t xs
data HList :: [*] -> * where
HNil :: HList '[]
HCons :: a -> HList as -> HList (a ': as)
When I actually tried to do this with a few types, I ran into a problem. The type-function " argument to TypeMap has to take the HList
element type as its last argument and return a new type. This works okay sometimes:
test :: HList rqs -> HList (TypeMap ((,) Int) rqs)
test HNil = HNil
test (HCons x xs) = HCons (3,x) $ test xs
But what if I wanted to switch the order of the tuple in the definition of test? My first attempt was to define a type synonym:
type RevIntTup b = (b,Int)
test2 :: HList rqs -> HList (TypeMap RevIntTup rqs)
test2 HNil = HNil
test2 (HCons x xs) = HCons (x,3) $ test2 xs
But of course, you can't partially apply type synonyms, which would certainly do the trick. Is there any (other) way to achieve this?
Upvotes: 2
Views: 696
Reputation: 21811
aavogt's answer certainly got the job done, but I discovered an alternate solution using Data.Promotion
from the singletons library. This library already includes type families for Flip
, Map
, $
, and much of the rest of the Prelude.
For example,
test2 :: HList rqs -> HList (Map (FlipSym1 (TyCon2 (,)) $ Int) rqs)
test2 HNil = HNil
test2 (HCons x xs) = HCons (x,3) $ test2 xs
which is comes almost directly from this amazing answer.
Upvotes: 1
Reputation: 1308
You should be able to write a FlipTypeMap
... but that's not very composable. A better choice here might be to do the type-level version of map ($ 2) (map (/) [1,2,3])
instead of map (flip (/) 2) [1,2,3]
by taking advantage of -XPolyKinds
:
type family TypeMap (a :: j -> k) (xs :: [j]) :: [k]
type instance TypeMap t '[] = '[]
type instance TypeMap t (x ': xs) = t x ': TypeMap t xs
type family ApList (xs :: [j -> k]) (a :: j) :: [k]
type instance ApList '[] t = '[]
type instance ApList (x ': xs) t = x t ': ApList xs t
test2 :: HList rqs -> HList (TypeMap (,) rqs `ApList` Int)
test2 HNil = HNil
test2 (HCons x xs) = HCons (x,3) $ test2 xs
Upvotes: 2