2012-09-09 31 views
6

Ho iniziato questa nuova domanda poiché è diventata un seguito dalla mia precedente domanda.Utilizzo dei tipi di dati in Haskell

Se ho due tipi di dati che sono composti da costruttori simili:

data A = X | Y | Z 
data B = X | Y 

c'è nessun modo posso in qualche modo rappresentare questo come:

data A = C | Z 
data B = C 

data C = X | Y 

se si può vedere quello che sto facendo - Sto cercando di raggruppare X | Y in un tipo di dati, che può quindi essere utilizzato da più altri tipi di dati. Non riesco a ottenere il compilatore per consentire questo, o se lo fa, non posso pattern-match contro la X o Y, solo la C ??

Viene visualizzato il messaggio di errore che C è stato dichiarato più volte.

Ho pensato che potrei forse usare i tipi, ma non consentono più tipi di battitura.

EDIT

Anche se dichiaro la via più lunga (come qui di seguito), ma ancora non compilerà e dice X e Y hanno più dichiarazioni:

data A = X | Y | Z 
data B = X | Y 
+0

Quello che stai chiedendo sarebbe un sottotipo di 'A '. Non verrebbe dichiarato con la parola chiave 'data', che crea un nuovo tipo, disgiunto dai precedenti tipi esistenti. Non penso che Haskell abbia una tale caratteristica, ma non sono al corrente con tutte le estensioni Haskell. – Gilles

+0

@Gilles: No, Haskell non ha alcun polimorfismo di sottotipo. Ha solo polimorfismo parametrico e polimorfismo ad-hoc attraverso classi di tipi. La cosa più vicina che puoi ottenere è un tipo esistenziale, ma è quasi, ma non del tutto, una cosa completamente diversa. –

+0

Lo metterei come risposta, ma perché non è del tutto ... Potresti essere in grado di avvicinarti a ciò che vuoi dichiarando una classe di caratteri e quindi le operazioni che ti servono per quelle "cose ​​comuni". Questo è un modo abbastanza comune per capovolgere le cose per risolvere (una versione di) questo problema .. –

risposta

13

non solo non si può fare anche tu non puoi fare la tua prima opzione - cioè non puoi avere due tipi nello stesso modulo che entrambi hanno costruttori chiamati X e Y.

Se si potesse fare questo, quale dovrebbe essere il tipo di X essere - C, A o B? La risposta più ovvia sarebbe C, ma in questo caso non sarebbe possibile utilizzarlo in un contesto in cui è richiesto un A o un B (si noti che Haskell non ha sottotipizzazione), in modo da annullare lo scopo dell'intero costrutto.

Il meglio che puoi fare è quello di avvolgere C in un costruttore di A e B, vale a dire:

data A = AC C | Z 
data B = BC C 
data C = X | Y 

Poi si potrebbe avvolgere un C sia con il AC o il costruttore BC per creare un valore di tipo A o B rispettivamente.

+0

Appena modificato per dire che la mia prima opzione non funziona. Quando dici "wrap" intendi letteralmente "includere qualche altro frammento di sintassi davanti a C, per distinguere dal C originale"? – Lethi

+2

@Dan Sì. Nel mio esempio, scrivere 'AC X' per creare un valore di tipo' A' e 'BC X' per creare il valore di tipo' B'. 'X' da solo non può avere due tipi diversi. – sepp2k

4

La ragione per cui non si può fare questo

data A = X | Y | Z 
data B = X | Y 

è la seguente. Di che si scrive codice seguito:

foo n = (n,X) 

che costruisce una coppia costituita n nel primo slot e X nel secondo slot. Che tipo dovrebbe inferire il compilatore? Un tipo valido sarebbe

foo :: a -> A -> (a,A) 

dal X è un costruttore di tipo A, ma ugualmente valido è

foo :: a -> B -> (a,B) 

dal X è un costruttore di tipo B.Se si hanno due costruttori con lo stesso nome, non è possibile dedurre un tipo unico per le funzioni che li utilizzano. Quindi non ti è permesso dare a due costruttori nello stesso modulo lo stesso nome.

1

Non si può fare questo:

data A = C | Z 
data B = C 

data C = X | Y 

(Per inciso, se B è identico-C, allora perché hanno B a tutti?)

Ma che cosa si può fare è qualcosa di simile:

data A = A_Other C | Z 
data B = B_Other C 

data C = X | Y 

Quindi È possibile abbinare modello come questo:

foo :: A -> String 
foo (A_Other X) = "X" 
foo (A_Other Y) = "Y" 
foo (  Z) = "Z" 

bar :: B -> String 
bar (B_Other X) = "X" 
bar (B_Other Y) = "Y" 

foobar :: C -> String 
foobar X = "X" 
foobar Y = "Y" 

Se questo ha un senso ...

0

Non si può fare ciò che si vuole, perché si dichiara più costruttori di dati. In

data A = X | Y | Z 

In realtà si sta introducendo il tipo A che ha 3 costruttori (valori) X, Y e Z. Questo è il motivo per cui il tuo primo pezzo di codice non verrà compilato, vedrà lo stesso nome elencato come costruttori per due tipi diversi! Se si potesse fare questo ci si deve chiedere se stessi è

X :: A 

o

X :: B 

, che in un contesto non orientata agli oggetti è spaventoso! Quindi è necessario fornire diversi nomi di costruttori per condividere i dati sottostanti, C.

Se volete questo fattore, si può fare come gli altri posti hanno suggerito ed i dati ceduti-out nei costruttori unici per ogni tipo di dati

data A = CForA C | Z 
data B = CForB C 

data C = X | Y 
Problemi correlati