受约束的异构列表

时间:2017-09-12 01:27:02

标签: haskell types hlist constraint-kinds

我搜索了Hackage并且找不到类似下面的东西,但它似乎相当简单和有用。是否有包含各种数据类型的库?

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

我找到的所有HLists都可以有任何类型,并且没有受到约束。

如果我没有自己上传。

3 个答案:

答案 0 :(得分:9)

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

  • 如果你真的希望a具有存在资格,我认为你应该使用常规列表。这里更有趣的数据类型是Exists,虽然我确定它已经存在于 package Hackage中的变种:

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

    然后,您的HList c[Exists c]同构,您仍然可以使用所有常用的基于列表的功能。

  • 另一方面,如果您不一定希望a中的(:-) :: 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 中的所有类型满足约束时才有效:

    getAllNews() {
    
        if(this.newslist != null) {
          return Observable.of(this.newslist);
        } 
    
        else {
          const authToken = localStorage.getItem('auth_token'); 
          const headers = new HttpHeaders() 
          .set('Content-Type', 'application/json') 
          .set('Authorization', `Bearer ${authToken}`);
    
          return this.httpClient
            .get('samplei/news/', { headers: headers })
            .map((response => response))
            .do(newslist => this.newslist = newslist)
            .catch(e => {
                if (e.status === 401) {
                    return Observable.throw('Unauthorized');           
                }
    
            });
        }
      }
    
    
      getNews(id: number) { 
        return this.getAllNews().map((data:any)=> data.data.data.find(news => news.id === id)) 
      }
    

答案 1 :(得分:5)

generics-sop套餐提供开箱即用的功能。

可以使用

generics-sop中定义异构列表
data NP :: (k -> *) -> [k] -> * where
  Nil  :: NP f '[]
  (:*) :: f x -> NP f xs -> NP f (x ': xs)

并将其实例化为标识类型构造函数I(来自generics-sop)或Identity(来自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

答案 2 :(得分: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 xsHKList (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

我之前已经为各种项目写了几次,但直到Kosmikus pointed out that it's in generics-sop我都不知道它是在图书馆的任何地方。