2012-09-09 3 views
6

J'ai commencé cette nouvelle question car elle est devenue une suite de ma question précédente.Utilisation de types de données dans Haskell

Si j'ai deux types de données qui sont composés de constructeurs similaires:

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

est-il pas moyen que je peux en quelque sorte représenter cela comme:

data A = C | Z 
data B = C 

data C = X | Y 

si vous pouvez voir ce que je fais - J'essaie de grouper les X | Y en un type de données, qui peut ensuite être utilisé par plusieurs autres types de données. Je ne peux pas sembler obtenir le compilateur pour permettre cela, ou si c'est le cas, je ne peux pas faire correspondre le modèle contre le X ou Y, seulement le C ??

Je reçois le message d'erreur que C a été déclaré plusieurs fois.

Je pensais que je pourrais peut-être utiliser des types, mais ils ne permettent pas plusieurs typages.

EDIT

Même si je déclare le long chemin (comme ci-dessous), elle ne sera pas compiler et dit X et Y ont plusieurs déclarations:

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

Qu'est-ce que vous demandez serait un sous-type de 'A '. Il ne serait pas déclaré avec le mot clé 'data', qui crée un nouveau type, disjoint des types existants antérieurs. Je ne pense pas que Haskell ait une telle fonctionnalité, mais je ne suis pas au courant de toutes les extensions Haskell. – Gilles

+0

@Gilles: Non, Haskell n'a aucun polymorphisme de sous-type. Il a seulement un polymorphisme paramétrique, et un polymorphisme ad-hoc à travers les classes de types. La chose la plus proche que vous pouvez obtenir est un type existentiel, mais c'est presque, mais pas tout à fait, une chose entièrement différente. –

+0

Je mettrais cela comme une réponse, mais parce que ce n'est pas tout à fait .. Vous pouvez être en mesure de se rapprocher de ce que vous voulez en déclarant une classe de type et ensuite les opérations dont vous avez besoin pour ces "choses courantes". C'est un moyen assez commun de retourner les choses pour résoudre (une version de) ce problème .. –

Répondre

13

Non seulement tu ne peux pas faire ceci, vous ne pouvez pas faire votre première option - c.-à-d. vous ne pouvez pas avoir deux types dans le même module qui ont tous deux constructeurs nommés X et Y.

Si vous pouviez le faire, quel devrait être le type de X - C, A ou B? La réponse la plus évidente serait C, mais vous ne pourrez pas l'utiliser dans un contexte où un A ou un B sont requis (notez que Haskell n'a pas de sous-typage), ce qui annulerait le but de la construction entière.

Le mieux que vous pouvez faire est d'envelopper C dans un constructeur de A et B, à savoir: Ensuite, vous pouvez envelopper un

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

C soit avec le AC ou le constructeur BC pour créer une valeur de type A ou B respectivement.

+0

Juste édité pour dire que ma première option ne fonctionne pas. Quand vous dites "wrap" vous voulez dire littéralement "inclure un autre morceau de syntaxe devant C, à distinguer du C d'origine"? – Lethi

+2

@Dan Oui. Dans mon exemple, vous écrivez 'AC X' pour créer une valeur de type' A' et 'BC X' pour créer une valeur de type' B'. 'X' par lui-même ne peut pas avoir deux types différents. – sepp2k

4

La raison pour laquelle vous ne pouvez pas le faire

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

est le suivant. Disons que vous écrire du code plus tard:

foo n = (n,X) 

qui construit une paire consistant en n dans la première fente et X dans la seconde fente. Quel type le compilateur doit-il déduire? Un type valide serait

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

depuis X est un constructeur de type A, mais tout aussi valable est

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

depuis X est un constructeur de type B.Si vous avez deux constructeurs avec le même nom, vous ne pouvez pas déduire un type unique pour les fonctions qui les utilisent. Vous n'êtes donc pas autorisé à donner le même nom à deux constructeurs du même module.

1

Vous ne pouvez pas le faire:

data A = C | Z 
data B = C 

data C = X | Y 

(En aparté, si B est identique-C, alors pourquoi ont B du tout?)

Mais ce que vous pouvez faire est quelque chose comme ceci:

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

data C = X | Y 

Puis vous pouvez faire correspondre modèle comme celui-ci:

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" 

Si cela est logique ...

0

Vous ne pouvez pas faire ce que vous voulez parce que vous déclarez plusieurs constructeurs de données. Dans

data A = X | Y | Z 

Vous introduisez en fait le type A qui dispose de 3 constructeurs (valeurs) X, Y et Z. C'est pourquoi votre premier morceau de code ne compilera pas, il voit le même nom listé comme constructeurs pour deux types différents! Si vous pouviez faire cela, vous auriez à vous demander est

X :: A 

ou

X :: B 

qui, dans un contexte non orienté objet est effrayant! Vous devez donc fournir des noms de constructeurs différents pour partager ces données sous-jacentes, C.

Si vous voulez ce facteur, vous pouvez faire comme les autres postes ont suggéré et les données affacturées-out dans les constructeurs uniques pour chaque type de données

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

data C = X | Y 
Questions connexes