Haskell 从类型级别列表创建值列表

Haskell 从类型级别列表创建值列表,haskell,type-level-computation,Haskell,Type Level Computation,我有一个这样的类型级别列表 data TList (ixs :: [*]) (f :: * -> *) where TNil :: TList '[] f (:-:) :: f ix -> TList ixs f -> TList (ix ': ixs) f genTList (Foo Int :-: Foo String) generate = Bar :-: Bar 我正在尝试使用现有的TList生成一个新的TList。 这个想法是要有一个功能 genTLis

我有一个这样的类型级别列表

data TList (ixs :: [*]) (f :: * -> *) where
  TNil  :: TList '[] f
  (:-:) :: f ix -> TList ixs f -> TList (ix ': ixs) f
genTList (Foo Int :-: Foo String) generate = Bar :-: Bar
我正在尝试使用现有的TList生成一个新的TList。 这个想法是要有一个功能

genTList :: TList ixs f -> t -> TList ixs g
其中't'是能够构造'gx'类型值的函数,其中'x'是列表'ixs'中的一种类型

那么

data Foo x
和(某种)

我可以得到这样的东西

data TList (ixs :: [*]) (f :: * -> *) where
  TNil  :: TList '[] f
  (:-:) :: f ix -> TList ixs f -> TList (ix ': ixs) f
genTList (Foo Int :-: Foo String) generate = Bar :-: Bar
因此,基本上,对于类型列表中的每个项目“x”,我希望有一个类型“Bar x” 也可以用无参数构造函数构造它的值,因为我知道 “Bar x”没有构造函数参数

我试图实现某个东西(),但它无法(合理地)进行类型检查

那么我应该如何处理这个问题呢?

您定义

class TListGen ixs (g :: * -> *) where
  genTList :: Proxy ixs -> g ix -> TList ixs g
但这意味着函数的调用方可以选择实例化所有类型变量的方法,尤其是如何实例化
ix

那么比如说,

genTList (Proxy :: Proxy '[Int, String]) (Just False)
将是此函数的类型正确调用,选择
g
作为
Maybe
ix
作为
Bool
。但这不可能是正确的。我们需要传递一个足够多态的东西,它至少适用于类型级别列表中出现的所有元素,甚至更好,适用于任何可能的
ix
选择。这就是排名2的多态类型所实现的:

class TListGen ixs (g :: * -> *) where
  genTList :: Proxy ixs -> (forall ix . g ix) -> TList ixs g
这需要
RankNTypes
语言扩展

现在,调用方只能传递参数类型为
g
的多态函数。所以传递
仅仅是False将不再有效,但是传递
什么都不传递也可以

案例的定义原则上是可以的,但实际上可以删除
OVERLAPS
pragma甚至代理参数,因为没有重叠,并且
ixs
可以从结果类型推断出来,因为它作为
TList
数据类型的参数出现:

class TListGen ixs (g :: * -> *) where
  genTList :: (forall ix . g ix) -> TList ixs g

instance TListGen '[] g where
  genTList _ = TNil

instance TListGen ixs g => TListGen (ix ': ixs) g where
  genTList g = g :-: genTList g
现在我们可以尝试使用它:

GHCi> genTList Nothing :: TList '[ Int, String ] Maybe
不幸的是,这会导致错误,因为没有
Show
实例:

• No instance for (Show (TList '[Int, String] Maybe))
    arising from a use of ‘print’
• In a stmt of an interactive GHCi command: print it
TList
定义
Show
实例是可能的,但有点棘手

我不确定这是否主要是一个练习,但是如果您只需要重用代码,那么所有这些都可以在包中使用

您的
TList
称为
NP
(参数按翻转顺序排列),您的
genTList
称为
pure\u NP
,因此您可以编写

GHCi> import Generics.SOP.NP
GHCi> pure_NP Nothing :: NP Maybe '[ Int, String ]
Nothing :* (Nothing :* Nil)

谢谢这确实是半个练习,但主要是我希望减少依赖性并保持简单。