Disons que j'ai trois constructeurs de valeur:constructeur une valeur appartenant à deux types différents
A { a :: Int }
B { b :: Char }
C { c :: Bool }
Je voudrais créer deux types X
et Y
telle qu'une valeur de type X
peut être un A
, B
ou C
, quelque chose comme ceci:
data X = A {...} | B {...} | C {...}
et une valeur de type Y
ne peut être qu'un A
ou B
, quelque chose comme ceci:
data Y = A {...} | B {...}
pour que je puisse coder quelque chose comme ceci:
foo :: X -> Int -- can pattern match
foo (A _) = 1
foo (B _) = 2
foo (C _) = 3
bar :: Y -> Bool -- also can pattern match with the same constructors
bar (A _) = true
bar (B _) = false
baz = A 1 -- baz is inferred to be a type that can fit in both X and Y
Je sais que je peux envelopper les constructeurs dans les définitions de X
et Y
comme celui-ci:
data X = XA A | XB B | XC C
data Y = YA A | YB B
mais cela semble désordonné (devoir taper XA A
etc tout le temps). Je pourrais étendre le contenu de A
, B
, et C
dans les définitions de X
et Y
, mais A
etc. sont assez compliqués et je préférerais ne pas dupliquer la définition. Est-ce possible avec Haskell, y compris les extensions GHC?
Modifier
Il semble que GADTs peut répondre à ma question posée (donc je marqué la réponse du radiateur comme correct), mais ne sont pas assez souples pour ce que je dois. Par exemple, pour autant que je sache, vous ne pouvez pas faire quelque chose comme:
func1 :: [XY Y_] -- returns a list of items that can only be A or B
func1 = ...
func2 = func1 ++ [C True] -- adding a C item to the list
func2
doivent être dactylographiés comme [XY X_]
, mais cela est impossible dans Haskell (à moins que mon expérience a eu tort). Après plus de recherches sur le web, ce que je veux vraiment, ce sont les variantes polymorphes d'OCaml qui (pour autant que je sache) n'existent qu'en OCaml (en regardant les langages plus «pratiques» que «académiques»).
Modifier 2
Voir la réponse de comonad. Il semble que cela peut vraiment être fait, mais je pense que je ferais mieux de ne pas réécrire cette question trop de fois. :-)
Vos définitions de 'foo' et' bar' ne taperont pas check, parce que 'A _' est par définition une valeur de type' A', pas 'X' ou' Y'. Vous ne pouvez pas avoir un autre type ('X') avec le même constructeur. – sastanin
Une autre façon de le regarder: quel type A aurait? Il ne peut en avoir qu'un, donc il ne peut pas être 'Int -> X' et' Int -> Y' simultanément. –
jetxee et Antal S-Z: Je sais que mes définitions de 'foo' et' bar' ne seront pas typecheck, mais j'espérais que quelque chose de similaire serait valide Haskell. Par exemple, avec typeclasses, 'read x' (où' x' est un 'String') peut avoir (dans un sens) plus d'un type. – yondalf