54 votes

Pourquoi Haskell manque-t-il des classes "évidentes"?

Considérer les Langages Orientés Objet:

La plupart des gens à venir à partir d'une programmation orientée objet arrière-plan, sont familiers avec la commune et des interfaces intuitives en différentes langues, qui capture l'essence de Java Collection & List interfaces. Collection se réfère à une collection d'objets qui ne sont pas nécessairement un ordre naturel et d'indexation. Un List est une collection qui a un ordre naturel et d'indexation. Ces interfaces abstraites de nombreuses données de la bibliothèque-structures en Java, de même que leur équivalent interfaces dans d'autres langues, et d'une compréhension intime de ces interfaces sont nécessaires pour travailler efficacement avec la plupart des données de la bibliothèque-structures.

Transition à Haskell:

Haskell est un type de système de classe qui agit sur les types, par analogie, à des interfaces des objets. Haskell semble avoir une bien conçue type de classe de la hiérarchie à l'égard de Foncteurs, Applicative, les Monades, etc. lorsque le type égard de la fonctionnalité. Il est évident qu'ils veulent corriger et bien captée par type de classes. Pourtant, quand vous regardez beaucoup de Haskell conteneurs (List,Map,Sequence,Set,Vector), ils étaient presque tous très similaires (ou identiques) fonctions, mais ne sont pas une abstraction par type de classes.

Quelques Exemples:

  • null pour le test de "vide"
  • length/size pour l'élément de comptage
  • elem/member pour l'ensemble de l'inclusion
  • empty et/ou singleton pour défaut de construction
  • union pour l'ensemble de l'union
  • (\\)/diff de différence
  • (!)/(!!) dangereux pour l'indexation (fonction partielle)
  • (!?)/lookup pour la sécurité de l'indexation (total de la fonction)

Si je veux utiliser l'une des fonctions ci-dessus, mais j'ai importé deux ou plusieurs récipients je dois commencer à cacher fonctions à partir des modules importés, ou explicitement importer uniquement les fonctions nécessaires à partir de modules ou de qualification les modules importés. Mais étant donné que toutes les fonctions fournissent la même fonctionnalité logique, il semble juste comme une corvée. Si les fonctions ont été définies à partir de type de classes, et non pas séparément dans chaque module, le compilateur de l'inférence de type mécanique pourrait résoudre ce problème. Il permettrait également de commutation des conteneurs sous-jacents simple aussi longtemps que ils ont partagé le type de cours (c'est à dire: vous permet de simplement utiliser un Sequence au lieu de List pour un meilleur accès aléatoire de l'efficacité).

Pourquoi ne pas Haskell ont un Collection et/ou Indexable type de classe(es) pour unifier & généraliser certaines de ces fonctions?

39voto

Warbo Points 502

Comme d'autres réponses ont souligné, Haskell tend à utiliser le vocabulaire différent. Cependant, je ne pense pas qu'ils ai expliqué la raison de la différence très bien.

Dans un langage comme Java, les fonctions ne sont pas "de première classe des citoyens"; il est vrai que les fonctions anonymes sont disponible dans les dernières versions, mais ce style d'interface (Collecte, Indexable, Interable, etc.) ont été conçus avant que.

Cela rend difficile de passer notre code, alors nous préférons les données d'autres personnes à être passées à notre code. Par exemple:

  • Les données de la mise en œuvre de Java Iterable vous permet de nous écrire for (Foo x : anIterable) { ... }
  • Les données de la mise en œuvre de PHP ArrayAccess vous permet de nous écrire anArrayAccess[anIndex]

Ce style peut aussi être vu dans les langages à objets qui mettent en œuvre des générateurs, puisque c'est une autre façon pour nous d'écrire for yieldedElement in aGenerator: ....

Haskell prend une approche différente avec ses typeclasses: nous préférons notre code pour être transmis à d'autres personnes. Certains (simplifié) exemples:

  • Functors accepter notre code et de l'appliquer à tous les éléments qu'ils "contiennent"
  • Monads accepter notre code et de l'appliquer dans une sorte de "séquence"
  • Foldables accepter notre code et l'utiliser pour 'réduire' leur contenu

Java doit seulement Iterable depuis que nous avons d'appeler notre code dans notre for boucle, de sorte que nous pouvons nous assurer qu'il est appelé correctement. Haskell nécessite plus spécifiques typeclasses depuis quelqu'un d'autre code sera l'appel de la nôtre, nous avons donc besoin de spécifier la façon dont il devrait être appelé; c'est un map, un fold, une unfold, etc.?

Heureusement, le type de système nous aide à choisir la bonne méthode ;)

36voto

danidiaz Points 4873

L' lens paquet fournit de cette.

  • Test de vacuité, de la création de conteneurs vides sont fournis par l' AsEmpty typeclass de Control.Lens.Empty.

  • L'accès aux éléments clés/index. L' At et Ixed typeclasses de Control.Lens.At.

  • La vérification de l'appartenance à définir-comme des conteneurs. L' Contains typeclass de Control.Lens.At.

  • L'ajout et la suppression d'éléments de la séquence comme des conteneurs. L' Cons et Snoc typeclasses de Control.Lens.Cons.

Aussi, l' pure méthode de Applicative typeclass peut souvent être utilisé pour créer des "singleton" conteneurs. Pour les choses qui ne sont pas foncteurs/applicatifs en Haskell, comme Set, peut - point de Data.Pointed pourrait être utilisé.

26voto

Toxaris Points 3265

Haskell a certains type de classes pour travailler avec des collections dans le forfait de base: Functor, Pliable et Traversable peut être utile pour travailler avec les collections, et le Monoïde, Applicative et/ou Alternative typeclasses peut être utile pour la construction des collections.

Ensemble, ces cours couvrent la plupart des opérations mentionnées dans la question, mais peut-être moins efficace qu'un conteneur spécifique à la fonction.

null pour le test de "vide"

Non pris en charge directement, mais Pliable soutient any (const True) ou constructions similaires.

longueur/taille pour l'élément de comptage:

Non pris en charge directement, mais Pliable soutient getSum . fold . fmap (const (Sum 1)) ou constructions similaires.

elem/membre pour l'ensemble de l'inclusion

Pliable soutient elem, notElem et member.

vide et/ou d'un singleton pour défaut de construction

Pour le vide, n'est - mempty de Monoïde et empty de l'Alternative. Pour singleton, n'est - pure d'Applicatifs.

l'union pour l'ensemble de l'union

Il est mappend de Monoïde et <|> de l'Alternative. Ils n'ont pas nécessairement de mettre en œuvre ensemble de l'union, mais ils mettent en œuvre une certaine forme d'union qui travaille bien ensemble avec le vide et généralement aussi avec un singleton et trouver.

(\)/diff de différence

Cette dernière n'est pas prise en charge, malheureusement.

(!)/(!!) pour dangereux d'indexation (fonction partielle)

Vous pouvez utiliser fromJust avec une fonction pour la sécurité de l'indexation.

(!?)/de recherche pour la sécurité de l'indexation (total de la fonction)

Il est find de Pliable.

21voto

jcast Points 948

En partie, la raison en est que les monades et les flèches sont les nouvelles fonctionnalités innovantes de Haskell, tandis que les collections sont relativement plus terre à terre. Haskell a une longue histoire comme un langage de recherche; d'intéressantes questions de recherche (conception monade instances & la définition générique des opérations de monades) obtenir plus d'effort de développement de "industrielle" polissage (définition de conteneur Api).

En partie, la raison est que ces types de venir à partir de trois différents forfaits (de base, les conteneurs et vector), avec trois histoires et des designers. Qui rend plus difficile pour les concepteurs pour coordonner sur la fourniture d'instances d'un seul type de classe.

En partie, la raison en est que la définition d'un seul type de classe pour couvrir tous les cinq, les conteneurs que vous avez mentionné est vraiment dur. Liste, de Séquence et de Vecteur sont relativement similaires, mais la Carte et le Jeu ont complètement différentes contraintes. Pour la Liste, de Séquence et de Vector, vous voulez qu'un simple constructeur de la classe, mais pour un Jeu qui ne marche pas, depuis le Jeu nécessite un Ord exemple sur le type d'élément. Pire encore, la Carte peut supporter la plupart de vos méthodes, mais son singleton fonction a besoin de deux paramètres, où le reste besoin d'un seul.

13voto

user3340662 Points 106

Ces typeclasses existe pas dans la norme Haskell, mais ils n'ont pas le même nom que leur équivalent OO homologues. L' Collection typeclass, par exemple, est appelé Foldable en Haskell. Vous pouvez l'utiliser pour tester si une structure est vide (foldr (const False) True x) ou de compter le nombre d'éléments (foldMap (const 1) x), ou pour tester l'appartenance (foldr (\e' present -> (e==e') || present) False x pour certains e).

Pour des opérations comme élément de recherche, vous avez l' Array typeclass qui pourrait fonctionner pour les données séquentielles. Pour plus de flexibilité, vous pouvez écrire votre propre Indexable classe, comme ceci par exemple (méfiez-vous des lentilles) :

class Indexable m k a where
  at :: k -> Lens' m (Maybe a)

L'élément null et l'ensemble de l'union appartiennent à l' Monoid typeclass (où mappend == union). Dans cette optique, la différence pourrait également être mis en œuvre dans son propre typeclass Differentiable (ce qui j'en suis sûr, il existe déjà dans des dizaines de Haskell bibliothèques) et nous avons une totale compatibilité avec les langages impératifs.

Haskell, par la vertu d'être conçu par les mathématiciens et autres, ne pas employer le même vocabulaire que la plupart des autres langues, mais rassurez-vous, cela ne signifie pas que ce n'est pas une pratique de la langue en plus d'être un impressionnant :-)

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