Ich habe diese heterogene Liste, deren Typ die Typen der darin enthaltenen Werte widerspiegelt. Ich kann durch Überprüfung aller Elemente in Strings umwandeln, dass jede Art erfüllt eine Einschränkung enthalten:Deko-Typ-Ebenenliste mit zusätzlichen Informationen aus der Typ-Level-Map
{-# 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
Was ich in der Lage sein möchten, wird über eine Typ-Ebene Assoziationsliste einige zusätzliche Informationen zu tun geben, das ist durch die Typen im HList indiziert. Etwas wie:
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)
Nun, es ist klar zu sehen, dass, wenn (Keys keyMap)
nicht leer ist, dann keyMap
, aber GHC kämpft dies herausgefunden:
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
Wie kann ich das so umschreiben, dass GHC kann Dinge herausfinden?
Sie können nicht mit einer Art Familie - das '(Symbol *)' werden von unendlich viele Arten bewohnt, die nicht von der Form sind ' '(_, _)' (zB 'Any',' Jeder Any ', etc) -' Keys' und 'Values' müssen beide zu * classes * werden, in denen der Körper der Klasse * die Wahrheit der Constraints im Kopf und im Kontext annimmt, im Gegensatz zu * denen sie * bedarf der Fall einer Art Familienanwendung. Wenn Sie auf diese Beweise außerhalb der Klasse zugreifen möchten, müssen Sie eine Funktion in der Klasse haben, die eine Darstellung auf Werteebene eines solchen Beweises (in der Regel eine GADT) erstellt. – user2407038