2

这是上一个问题的后续:Type-level Map with DataKinds,从它收到的两个答案开始。

我的目标是采用HList任意类型并将其转换为相关/派生类型的列表

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)

当我实际上尝试使用几种类型来执行此操作时,我遇到了一个问题。TypeMap 的 type-function " 参数必须将HList元素类型作为其最后一个参数并返回一个新类型。这有时可以正常工作:

test :: HList rqs -> HList (TypeMap ((,) Int) rqs)
test HNil = HNil
test (HCons x xs) = HCons (3,x) $ test xs

但是如果我想在 test 的定义中切换元组的顺序呢?我的第一次尝试是定义一个类型同义词:

type RevIntTup b = (b,Int)

test2 :: HList rqs -> HList (TypeMap RevIntTup rqs)
test2 HNil = HNil
test2 (HCons x xs) = HCons (x,3) $ test2 xs

但是,当然,您不能部分应用 type synonyms,这肯定会奏效。有没有(其他)方法可以实现这一目标?

4

2 回答 2

2

你应该可以写一个FlipTypeMap... 但这不是很可组合。这里更好的选择可能是使用类型级别的版本 map ($ 2) (map (/) [1,2,3])而不是map (flip (/) 2) [1,2,3]利用-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
于 2013-10-06T22:12:59.513 回答
1

aavogt 的回答当然完成了工作,但我发现了一个使用Data.Promotion来自单例库的替代解决方案。这个库已经包含了FlipMap$和 Prelude 的大部分其他部分的类型族。

例如,

test2 :: HList rqs -> HList (Map (FlipSym1 (TyCon2 (,)) $ Int) rqs)
test2 HNil = HNil
test2 (HCons x xs) = HCons (x,3) $ test2 xs

这几乎直接来自这个惊人的答案

于 2014-06-05T13:17:44.233 回答