2012-04-17 13 views
26

Quando si utilizzano tipi Esistenziali, è necessario utilizzare una sintassi di corrispondenza del modello per l'estrazione del valore di forall ed. Non possiamo usare i normali selettori di record come funzioni. GHC segnala un errore e suggerire utilizzando pattern-matching con questa definizione di yALL:Perché non posso utilizzare selettori di record con un tipo quantificato in modo esistenziale?

{-# LANGUAGE ExistentialQuantification #-} 

data ALL = forall a. Show a => ALL { theA :: a } 
-- data ok 

xALL :: ALL -> String 
xALL (ALL a) = show a 
-- pattern matching ok 

-- ABOVE: heaven 
-- BELOW: hell 

yALL :: ALL -> String 
yALL all = show $ theA all 
-- record selector failed 

forall.hs:11:19: 
    Cannot use record selector `theA' as a function due to escaped type variables 
    Probable fix: use pattern-matching syntax instead 
    In the second argument of `($)', namely `theA all' 
    In the expression: show $ theA all 
    In an equation for `yALL': yALL all = show $ theA all 

Alcuni dei miei dati richiede più di 5 elementi. E 'difficile mantenere il codice se uso di pattern-matching:

func1 (BigData _ _ _ _ elemx _ _) = func2 elemx 

C'è un buon metodo per rendere il codice come quello mantenibile o per avvolgerlo in modo che posso usare un qualche tipo di selettori?

+3

Suggerimento: quale sarebbe il tipo di "theA"? –

+0

@Louis Wasserman: vuoi dire che usi la sintassi esistenziale in yALL? Come? – Nybble

+0

Fondamentalmente, la risposta è che non ha un tipo esplicito, quindi è necessario abbinare il modello per ottenere un tipo lavorabile. –

risposta

15

È possibile utilizzare la sintassi record nel pattern matching,

func1 BigData{ someField = elemx } = func2 elemx 

funziona ed è molto meno di battitura per i tipi enormi.

+0

Ottima risposta! L'ho appena trovato in seguito: data B {x :: Int, y :: Int}; divertimento B {..} = x + y; quella può essere un'alternativa. – Nybble

16

I tipi esistenziali funzionano in modo più elaborato rispetto ai tipi normali. GHC (giustamente) vieta di utilizzare theA come una funzione. Ma immagina che non ci sia un divieto del genere. Che tipo avrebbe questa funzione? Essa dovrebbe essere qualcosa di simile:

-- Not a real type signature! 
theA :: ALL -> t -- for a fresh type t on each use of theA; t is an instance of Show 

In estrema crudamente, forall rende GHC "dimenticare" il tipo di argomenti del costruttore; tutto ciò che il sistema di tipi sa è che questo tipo è un'istanza di Show. Pertanto, quando si tenta di estrarre il valore dell'argomento del costruttore, non è possibile ripristinare il tipo originale.

Quello che GHC fa, dietro le quinte, è ciò che dice il commento alla firma del tipo falso sopra: ogni volta che si associa il modello al costruttore ALL, la variabile associata al valore del costruttore viene assegnata a un tipo univoco che è garantito essere diverso da ogni altro tipo. Prendiamo ad esempio questo codice:

case ALL "foo" of 
    ALL x -> show x 

La variabile x ottiene un tipo unico che si distingue da ogni altro tipo di programma e non può essere abbinato con qualsiasi variabile di tipo. Questi tipi unici non sono autorizzati a sfuggire al livello superiore, motivo per cui theA non può essere utilizzato come funzione.

+5

In genere, si può pensare a un tipo esistenziale come tupla dipendente, dove il primo elemento è un tipo ('*') e il secondo è un valore di quel tipo - 'Σ [a: *] a'. Il problema è che quando si tenta di scrivere una firma di tipo per una proiezione del secondo elemento della tupla, è necessario conoscere il valore del primo elemento. Questo non può essere espresso in Haskell. Se hai un linguaggio tipizzato in modo dipendente puoi scriverlo come (usando la notazione Agda): '(x: Σ [a: *] a) → fst x'. – Vitus

+4

+1 Questo spiega il messaggio di errore "Impossibile utilizzare il selettore di record' theA 'come funzione ** a causa di variabili di tipo escape "**" –

Problemi correlati