【问题标题】:Decorating type level list with extra information from type level map使用类型级别映射中的额外信息装饰类型级别列表
【发布时间】:2016-10-10 18:59:22
【问题描述】:

我有这个异构列表,它的类型反映了它包含的值的类型。我可以通过检查包含的每种类型是否满足约束来将所有元素转换为字符串:

{-# LANGUAGE DataKinds #-}
{-# LANGUAGE GADTs #-}
{-# LANGUAGE TypeOperators #-}
{-# LANGUAGE KindSignatures #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE PolyKinds #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TypeApplications #-}   

import GHC.Exts
import GHC.TypeLits

import Data.Proxy

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

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

type family Keys (xs :: [(a, b)]) :: [a] where
    Keys '[] = '[]
    Keys ( '(a, b) ': xs) = a ': Keys xs

type family Values (xs :: [(a, b)]) :: [b] where
    Values '[] = '[]
    Values ( '(a, b) ': xs) = b ': Values xs

showHList :: AllSatisfy Show xs => HList xs -> [String]
showHList HNil = []
showHList (HCons x xs) = show x : showHList xs

我希望能够通过类型级别关联列表指定一些额外的信息,该列表由 HList 中的类型索引。类似的东西:

showWithKey :: forall (keyMap :: [(*, Symbol)]) (b :: Symbol) (rest :: [(*, Symbol)]).
               (AllSatisfy Show (Keys keyMap)
               ,AllSatisfy KnownSymbol (Values keyMap)
               ) =>
               Proxy keyMap -> HList (Keys keyMap) -> [(String, String)]
showWithKey _ HNil = []
showWithKey _ (HCons (x :: a) (xs :: HList as)) =
    let p = (Proxy @keyMap) :: Proxy ( '(a, b) ': rest )
    in (show x, symbolVal (Proxy @b)) : (showWithKey (Proxy @rest) xs)

现在,很明显如果(Keys keyMap) 不为空,则keyMap,但 GHC 很难弄清楚这一点:

Could not deduce: keyMap ~ ('(a, b) : rest)
      from the context: (AllSatisfy Show (Keys keyMap),
                         AllSatisfy KnownSymbol (Values keyMap))
        bound by the type signature for:
                   showWithKey :: (AllSatisfy Show (Keys keyMap),
                                   AllSatisfy KnownSymbol (Values keyMap)) =>
                                  Proxy keyMap -> HList (Keys keyMap) -> [(String, String)]
      or from: Keys keyMap ~ (a : as)
        bound by a pattern with constructor:
                   HCons :: forall a (as :: [ghc-prim-0.5.0.0:GHC.Types.*]).
                            a -> HList as -> HList (a : as),
                 in an equation for ‘showWithKey’
      ‘keyMap’ is a rigid type variable bound by
        the type signature for:
          showWithKey :: forall (keyMap :: [(ghc-prim-0.5.0.0:GHC.Types.*,
                                             Symbol)]) (b :: Symbol) (rest :: [(ghc-prim-0.5.0.0:GHC.Types.*,
                                                                                Symbol)]).
                         (AllSatisfy Show (Keys keyMap),
                          AllSatisfy KnownSymbol (Values keyMap)) =>
                         Proxy keyMap -> HList (Keys keyMap) -> [(String, String)]
      Expected type: Proxy ('(a, b) : rest)
        Actual type: Proxy keyMap 

我怎样才能重写这个,以便 GHC 可以解决问题?

【问题讨论】:

  • 你不能使用类型族——(Symbol, *) 类型被无数种不属于'( _, _) 形式的类型所占据(例如AnyAny Any 等)-@987654330 @ 和Values 必须都成为,其中类的主体假设头部和上下文中的约束的真实性,而不是要求 它们与类型族应用程序的情况一样。如果你想在类之外访问这些证明,你必须在类中有一个函数来构造这种证明的值级别表示(通常是 GADT)。

标签: haskell gadt type-families type-level-computation data-kinds


【解决方案1】:

根据 user2407038 所说的一些线索,我创建了 depMap 类型的具体表示,然后创建了一个类型类来描述该类型的一个不完全单一但至少规范的值。

{-# LANGUAGE DataKinds #-}
{-# LANGUAGE GADTs #-}
{-# LANGUAGE TypeOperators #-}
{-# LANGUAGE KindSignatures #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE PolyKinds #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TypeApplications #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE AllowAmbiguousTypes #-}

import GHC.Exts
import GHC.TypeLits

import Data.Proxy

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

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

type family Keys (xs :: [(a, b)]) :: [a] where
    Keys '[] = '[]
    Keys ( '(a, b) ': xs) = a ': Keys xs

type family Values (xs :: [(a, b)]) :: [b] where
    Values '[] = '[]
    Values ( '(a, b) ': xs) = b ': Values xs

showHList :: AllSatisfy Show xs => HList xs -> [String]
showHList HNil = []
showHList (HCons x xs) = show x : showHList xs

data SKeyMap :: [(*, Symbol)] -> * where
  SKeyNil :: SKeyMap '[]
  SKeyCons :: Proxy a -> Proxy s -> SKeyMap xs -> SKeyMap ( '(a, s) ': xs )

class KnownKeyMap (keyMap :: [(*, Symbol)]) where
    sKeyMap :: SKeyMap keyMap


instance KnownKeyMap '[] where
    sKeyMap = SKeyNil

instance KnownKeyMap keyMap => KnownKeyMap ( '(a, s) ': keyMap ) where
    sKeyMap = SKeyCons Proxy Proxy sKeyMap

showWithKey' :: forall (keyMap :: [(*, Symbol)]) .
               (AllSatisfy Show (Keys keyMap)
               ,AllSatisfy KnownSymbol (Values keyMap)
               ) =>
               SKeyMap keyMap -> HList (Keys keyMap) -> [(String, String)]
showWithKey' SKeyNil HNil = []
showWithKey' (SKeyCons _ sp skRest) (HCons (x :: a) (xs :: HList as)) =
    (show x, symbolVal sp) : (showWithKey' skRest xs)

showWithKey :: forall (keyMap :: [(*, Symbol)]) .
               (KnownKeyMap keyMap
               ,AllSatisfy Show (Keys keyMap)
               ,AllSatisfy KnownSymbol (Values keyMap)
               ) =>
               HList (Keys keyMap) -> [(String, String)]
showWithKey = showWithKey' (sKeyMap @keyMap)

【讨论】:

    猜你喜欢
    • 2023-03-18
    • 2019-10-20
    • 1970-01-01
    • 2021-10-20
    • 2017-02-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多