6

我搜索了 Hackage,找不到类似以下的内容,但它似乎相当简单且有用。是否有包含某种数据类型的库?

data HList c where
  (:-) :: c a => a -> HList c
  Nil :: HList c

我发现的所有 HList 都可以具有任何类型,并且不受限制。

如果没有我会上传我自己的。

4

3 回答 3

10

我不确定这种数据类型是否有用......

  • 如果您真的想a获得存在资格,我认为您应该使用常规列表。这里更有趣的数据类型是Exists,尽管我确信在Hackage包中已经有它的变体:

    data Exists c where
      Exists :: c a => a -> Exists c
    

    然后,你HList c是同构的[Exists c],你仍然可以使用所有常用的基于列表的函数。

  • 另一方面,如果您不一定希望ain(:-) :: c a => a -> HList c具有存在资格(将其作为这种方式违背了 的观点HList),则应改为定义以下内容:

    data HList (as :: [*]) where
      (:-) :: a -> HList as -> HList (a ': as)
      Nil :: HList '[]
    

    然后,如果您想要求HList满足的所有条目c,您可以创建一个类型类来见证注入,HList as仅当满足约束[Exists c]中的所有类型时,实例解析才有效:HList

    class ForallC as c where
      asList :: HList as -> [Exists c]
    
    instance ForallC '[] c where
      asList Nil = []
    
    instance (c a, ForallC as c) => ForallC (a ': as) c where
      asList (x :- xs) = Exists x : asList xs
    
于 2017-09-12T01:57:26.517 回答
5

generics-sop软件包开箱即用。

可以generics-sop通过使用定义异构列表

data NP :: (k -> *) -> [k] -> * where
  Nil  :: NP f '[]
  (:*) :: f x -> NP f xs -> NP f (x ': xs)

并将其实例化为身份类型构造函数I(from generics-sop) 或Identity(from Data.Functor.Identity)。

然后库提供约束All,例如

All Show xs => NP I xs

是异构列表的类型,其中所有包含的类型都在Show类中。从概念上讲,All是一个类型族,它为类型级列表中的每个元素计算约束:

type family All (f :: k -> Constraint) (xs :: [k]) :: Constraint where
  All c '[]       = ()
  All c (x ': xs) = (c x, All c xs)

(仅在实际定义中,All额外包装在类型类中,以便可以部分应用。)

NP该库还提供了在给定公共约束的情况下遍历和转换 s 的各种函数。

于 2017-09-12T06:23:43.807 回答
3

你真正想要的是

data HKList :: (k -> *) -> [k] -> * where
  Nil  :: HKList f '[]
  (:*) :: f x -> HKList f xs -> HKList f (x ': xs)

您可以将其用作普通的异构列表

type HList = HKList Identity

或者附加一些常量类型的额外信息e到每个值(或其他有趣的函子)

HKList ((,) e)

或者使用字典中捕获的额外信息

data Has c a where
    Has :: c a => a -> Has c a

type ConstrainedList c = HKList (Has c)

或者只保留捕获的约束列表

data Dict1 :: (k -> Constraint) -> k -> * where
  Dict1 :: c k => Dict1 c k

您可以使用它来定义满足约束的所有类型列表的想法

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

或者你可以用一种类型做的任何其他事情k -> *

All c xs => HList xs您可以在使用和工作之间自由转换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

完整代码

我之前为各种项目写过几次,但直到Kosmikus 指出它在generics-sop.

于 2017-09-12T15:09:07.053 回答