Haskell 使用来自类型级别映射的额外信息装饰类型级别列表
我有一个异构列表,它的类型反映了它包含的值的类型。通过检查包含的每个类型是否满足约束,我可以将所有元素转换为字符串:Haskell 使用来自类型级别映射的额外信息装饰类型级别列表,haskell,gadt,type-families,type-level-computation,data-kinds,Haskell,Gadt,Type Families,Type Level Computation,Data Kinds,我有一个异构列表,它的类型反映了它包含的值的类型。通过检查包含的每个类型是否满足约束,我可以将所有元素转换为字符串: {-# LANGUAGE DataKinds #-} {-# LANGUAGE GADTs #-} {-# LANGUAGE TypeOperators #-} {-# LANGUAGE KindSignatures #-} {-# LANGUAGE TypeFamilies #-} {-# LANGUAGE PolyKinds #-} {-# LANGUAGE ScopedTy
{-# 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能够解决问题?根据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)
您不能使用类型族-种类
(符号,*)
由无限多的类型所占据,这些类型的形式不是”(u,u)
(例如Any
,Any
,等等)键和值都必须成为类,类的主体假定头部和上下文中约束的真实性,而不是像类型族应用程序那样要求约束。如果要在类之外访问这些证明,则必须在类中具有一个函数,该函数构造此类证明的值级表示(通常为GADT)。