Un modo per affrontare questo problema consiste nel taggare i valori con i rappresentanti del tipo di runtime. Sto canalizzando Stephanie Weirich, qui. Facciamo un piccolo esempio. Per prima cosa, dai una rappresentazione ad alcuni tipi. Questo è in genere fatto con una costruzione singleton.
data Type :: * -> * where
Int :: Type Int
Char :: Type Char
List :: Type x -> Type [x]
Così Type Int
contiene un valore, che ho chiamato anche Int
, perché agisce come rappresentante di run-time di tipo Int
. Se è possibile vedere il colore anche nelle cose monocromatiche, lo ::
a sinistra dello ::
è rosso e lo Type
è blu dopo lo .
Ora possiamo eseguire il packaging esistenziale, preservando l'utilità.
data Cell :: * where
(:::) :: x -> Type x -> Cell
Un Cell
è un valore etichettato con un rappresentante runtime di questo tipo. Puoi recuperare l'utilità del valore leggendo il suo tag type. In effetti, poiché i tipi sono strutture di primo ordine, possiamo controllarli per l'uguaglianza in un modo utile.
data EQ :: k -> k -> * where
Refl :: EQ x x
typeEQ :: Type x -> Type y -> Maybe (EQ x y)
typeEQ Int Int = Just Refl
typeEQ Char Char = Just Refl
typeEQ (List s) (List t) = case typeEQ s t of
Just Refl -> Just Refl
Nothing -> Nothing
typeEQ _ _ = Nothing
Un uguaglianza booleana sui rappresentanti di tipo serve a nulla: abbiamo bisogno del test di uguaglianza per costruire il prove che i tipi rappresentate possono essere unificati. Con il test di prova-produzione, possiamo scrivere
gimme :: Type x -> Cell -> Maybe x
gimme t (x ::: s) = case typeEQ s t of
Just Refl -> Just x
Nothing -> Nothing
Naturalmente, scrivere i tag di tipo è un fastidio. Ma perché tenere un cane e abbaiare te stesso?
class TypeMe x where
myType :: Type x
instance TypeMe Int where
myType = Int
instance TypeMe Char where
myType = Char
instance TypeMe x => TypeMe [x] where
myType = List myType
cell :: TypeMe x => x -> Cell
cell x = x ::: myType
E ora siamo in grado di fare le cose come
myCells :: [Cell]
myCells = [cell (length "foo"), cell "foo"]
e quindi ottenere
> gimme Int (head myCells)
Just 3
Naturalmente, tutto sarebbe molto più ordinato, se non abbiamo dovuto fare lo costruzione singleton e potrebbe solo eseguire il pattern-match su tipi che potremmo scegliere di mantenere in fase di esecuzione. Mi aspetto che ci arriveremo quando il mitico quantificatore pi
diventa meno mitico.
Non hai collezioni eterogenee - il tipo "Box" è inutile. Non si può fare nulla con il valore all'interno, a parte chiamare 'seq' su di esso immagino .. Sembra che questa domanda non riguardi collezioni eterogenee in Haskell di per sé, ma la modellazione di un sistema di tipi in Haskell che supporti raccolte eterogenee.Tuttavia, se intendi "dinamico" come in "digitato dinamicamente", allora non ha senso per la rappresentazione di un linguaggio tipizzato dinamicamente da digitare staticamente nel meta-linguaggio (Haskell). – user2407038
Possibile duplicato di [Elenco di qualsiasi 'DataKind' in GADT] (http://stackoverflow.com/questions/28388715/list-of-any-datakind-in-gadt/). – user3237465