57 votes

Pourquoi Haskell types de données algébriques "fermé"?

Corrigez-moi si je me trompe, mais il semble que les types de données algébriques en Haskell sont utiles dans de nombreux cas où vous utiliseriez des classes et héritage dans les langages à objets. Mais il y a une grande différence: une fois qu'un type de données algébrique est déclaré, il ne peut pas être étendue ailleurs. Il est "fermé". Dans OO, vous pouvez étendre déjà défini les classes. Par exemple:

data Maybe a = Nothing | Just a

Il n'y a aucun moyen que je peux en quelque sorte ajouter une autre option pour ce type plus tard, sans modifier la présente déclaration. Quels sont donc les avantages de ce système? Il semble que l'OO serait beaucoup plus extensible.

80voto

Norman Ramsey Points 115730

La réponse a à voir avec de quelles façons le code est facile à étendre, une tension entre les classes et les types de données algébriques que philip Wadler surnommé ", l'expression "problème":

  • Avec des types de données algébriques,

    • Il est très bon marché pour ajouter une nouvelle opération sur les choses: vous venez de définir une nouvelle fonction. Toutes les anciennes fonctions sur les choses continuent à fonctionner sans modification.

    • Il est très coûteux d'ajouter un nouveau genre de chose: vous devez ajouter un nouveau constructeur d'un type de données existant, et que vous avez à modifier et recompiler à chaque fonction qui utilise ce type.

  • Avec des classes,

    • Il est très bon marché pour ajouter un nouveau genre de chose: il suffit d'ajouter une nouvelle sous-classe, et que vous aviez besoin de définir des méthodes spécialisées, dans cette classe, pour toutes les opérations existantes. La super-classe et tous les autres sous-classes de continuer à fonctionner sans modification.

    • Il est très coûteux d'ajouter une nouvelle opération sur les choses: vous devez ajouter une nouvelle déclaration de la méthode de la super-classe et éventuellement ajouter une définition de méthode pour chaque sous-classe existante. Dans la pratique, la charge varie en fonction de la méthode.

Ainsi, les types de données algébriques sont fermées à cause d'un type fermé prend en charge certains types de l'évolution du programme. Par exemple, si vos données types de définir une langue, il est facile d'ajouter de nouvelles passes de compilation sans invalider les anciens ou changer les données.

Il est possible d'avoir "ouvert" types de données", mais, sauf dans des circonstances soigneusement contrôlées, la vérification de type devient difficile. Todd Millstein fait quelques très beau travail sur un langage de conception qui prend en charge open algébrique de types et extensible fonctions, le tout avec un type modulaire checker. J'ai trouvé son livre un grand plaisir à lire.

67voto

Tom Lokhorst Points 7733

Le fait que l'ADT sont fermés le rend beaucoup plus facile à écrire total fonctions. Qui sont des fonctions qui produisent toujours un résultat, pour toutes les valeurs possibles de son type, par exemple.

maybeToList :: Maybe a -> [a]
maybeToList Nothing  = []
maybeToList (Just x) = [x]

Si Maybe étaient ouvertes, quelqu'un pourrait ajouter un constructeur supplémentaire et l' maybeToList fonction serait de se briser.

Dans OO ce n'est pas un problème, quand vous êtes à l'utilisation de l'héritage pour étendre un type, parce que quand vous appelez une fonction pour laquelle il n'y a pas de surcharge, il suffit d'utiliser la mise en œuvre d'une super-classe. I. e., vous pouvez appeler printPerson(Person p) de bons résultats avec un Student objet si Student est une sous-classe de Person.

En Haskell, vous devez généralement utiliser l'encapsulation et les classes de type lorsque vous en avez besoin à mesure de vos types. Par exemple:

class Eq a where
   (==) :: a -> a -> Bool

instance Eq Bool where
  False == False = True
  False == True  = False
  True  == False = False
  True  == True  = True

instance Eq a => Eq [a] where
  []     == []     = True
  (x:xs) == (y:ys) = x == y && xs == ys
  _      == _      = False

Maintenant, l' == la fonction est complètement ouverte, vous pouvez ajouter vos propres types en faisant une instance de l' Eq classe.


À noter qu'il y a eu des travaux sur l'idée de types de données extensibles, mais ce n'est certainement pas une partie de Haskell encore.

15voto

Dave Points 5879

Si vous écrivez une fonction comme

maybeToList Nothing = []
maybeToList (Just x) = [x]

alors vous savez que cela ne va pas produire une erreur d'exécution parce que vous avez couvert tous les cas. Cela cesse d'être vrai dès lors que le Peut-être le type est extensible. Dans le cas où vous avez besoin d'un extensible type (et ils sont plus rares que vous le pensez), l'canonique Haskell solution est d'utiliser un type de classe.

11voto

Don Stewart Points 94361

Cochez la case "Ouvrir les types de données et fonctions accessibles" http://lambda-the-ultimate.org/node/1453

Dans les langages orientés objet, il est facile à étendre les données, en définissant de nouvelles classes, mais il est difficile d'ajouter de de nouvelles fonctions. Fonctionnelle langues, la situation est inversée: l'ajout de nouvelles fonctions ne pose pas de des problèmes, mais l'extension de données (ajout d' de nouvelles données constructeurs) nécessite la modification du code existant. Le problème de les soutenir à la fois les directions de l'extensibilité est connu comme la l'expression de problème. Nous présentons open types de données et fonctions accessibles en tant que solution légère et à l'expression problème dans le langage Haskell. L' l'idée est que les constructeurs de l'open data les types, et les équations de fonctions accessibles peuvent apparaître dispersés à travers un programme. En particulier, ils peuvent résider dans différents modules. L' destiné sémantique est comme suit: le programme doit se comporter comme si les données les types et les fonctions ont été fermés, défini dans un seul endroit. L'ordre de la fonction est déterminé par les équations meilleur ajustement de la correspondance de modèle, où un modèle spécifique l'emporte sur une différence de un. Nous montrons que notre la solution est applicable à la l'expression de problème, générique la programmation, et les exceptions. Nous esquisse deux implémentations. Simple, dérivée de la sémantique, et un basé sur mutuellement récursives modules qui permet la compilation séparée.

7voto

rampion Points 38697

Tout d'abord, comme contrepoint à Charlie réponse, ce n'est pas intrinsèque à la programmation fonctionnelle. OCaml est le concept d' open syndicats ou des variantes polymorphes, qui vise essentiellement à faire ce que vous voulez.

Comme pour pourquoi, je crois que ce choix a été fait pour Haskell, parce que

  • cela permet de types prévisible - il en existe qu'un nombre fini de constructeurs pour chaque
  • il est facile de définir vos propres types.
  • de nombreux Haskell fonctions sont polymorphes, et les classes vous permettent d'étendre les types personnalisés pour s'adapter à des paramètres de fonction (pensez à Java les Interfaces).

Donc, si vous préférez avoir un data Color r b g = Red r | Blue b | Green g type, c'est facile à faire, et vous pouvez facilement le faire agir comme une monade ou un foncteur ou d'autres fonctions au besoin.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X