SomeNat
è esistenzialmente quantificata:
data SomeNat = forall n. KnownNat n => SomeNat (Proxy n)
che si legge come SomeNat
contiene, beh, "alcuni n :: Nat
". Proxy
è un singleton che consente di sollevare quello n
a livello di tipo per soddisfare il sistema di tipi - in un linguaggio tipizzato tipicamente abbiamo bisogno di tale costruzione molto raramente. Possiamo definire SomeNat
in modo più esplicito utilizzando GADTs
:
data SomeNat where
SomeNat :: forall n. KnownNat n => Proxy n -> SomeNat
Così SomeNat
contiene un Nat
, che non è noto staticamente.
Poi
someNatVal :: Integer -> Maybe SomeNat
legge come "someNatVal
riceve un Integer
e Maybe
restituisce un hiden Nat
". Non possiamo restituire uno KnownNat
, perché Known
significa "noto a livello di testo", ma non c'è nulla che sappiamo di un arbitrario Integer
a livello di testo.
L'inverso (modulo SomeNat
involucro ed un proxy
invece del Proxy
) di someNatVal
è
natVal :: forall n proxy. KnownNat n => proxy n -> Integer
si legge come "natVal
riceve qualcosa che hanno un Nat
nel suo genere e restituisce che Nat
convertito in Integer
".
I tipi di dati quantificati in modo approssimativo sono in genere used per il wrapping dei valori di runtime. Supponi di voler leggere uno Vec
(un elenco con una lunghezza nota staticamente) da STDIN
, ma come calcoli staticamente la lunghezza dell'input? Non c'è alcun modo. Quindi, avvolgi una lista, che hai letto, nel corrispondente tipo di dati quantificati esistenzialmente, dicendo "Non conosco la lunghezza, ma ne esiste una".
Tuttavia è eccessivo in molti casi. Per fare qualcosa con il tipo di dati quantificato esistenzialmente devi essere generale: ad es.se hai bisogno di trovare la somma di elementi di un SomeVec
devi definire sumVec
per Vec
s con lunghezza arbitraria. Quindi scartiamo lo SomeVec
e applichiamo sumVec
, dicendo "Non conosco la lunghezza di uno Vec
incartato, ma a sumVec
non interessa". Ma invece di questo wrapping-unwrapping puoi usare directly CPS.
Tuttavia a causa di questa generalità è necessario abilitare ImpredicativeTypes
per poter definire, ad esempio, un elenco con tali continuazioni. In tal caso, un elenco con dati quantificati in modo esistenziale è un common pattern che consente di aggirare lo ImpredicativeTypes
.
Per quanto riguarda il tuo esempio, con propriamente definito Nat
s, una versione che mette a confronto Nat
s è lazier, che una versione che mette a confronto Integer
s.
Non capisco il tuo esempio o quello che intende mostrare. Quello che sta succedendo non sta succedendo qui: 'let b = Bar" foo ":: Bar n in show b'? – jberryman
@jberryman La parte importante è da cui proviene 'n'. In che modo il tipo 'n' si avvicina esattamente al valore fornito in fase di esecuzione? I tipi esistono solo al momento della compilazione in Haskell, dopo tutto. * Questo * è ciò che 'someNatVal' fa. – Carl