Quelles sont les techniques que je pourrais utiliser pour refactoriser de manière cohérente le code en supprimant la dépendance aux types existentiels? Celles-ci sont généralement utilisées pour disqualifier les constructions non désirées de votre type, ainsi que pour permettre une consommation avec un minimum de connaissances sur le type donné (ou c'est ce que je comprends).
Quelqu'un a-t-il mis au point un moyen simple et cohérent de supprimer l'utilisation de ces codes dans le code tout en conservant certains des avantages? Ou au moins un moyen de glisser dans une abstraction qui permette de les supprimer sans nécessiter un manque de code important pour faire face à la modification?
Vous pouvez en savoir plus sur les types existentiels ici ("si vous osez ..").
la source
Réponses:
Les types existentiels ne sont pas vraiment considérés comme une mauvaise pratique en programmation fonctionnelle. Je pense que ce qui vous inquiète , c’est que l’une des utilisations les plus couramment citées des existentiels est l’ antipattern de la classe de types existentielle , ce que beaucoup de gens pensent être une mauvaise pratique.
Cette tendance est souvent mise au jour en réponse à la question de savoir comment avoir une liste d’éléments de type hétérogène implémentant la même classe de types. Par exemple, vous voudrez peut-être avoir une liste de valeurs qui ont des
Show
instances:Le problème avec un code comme celui-ci est le suivant:
AnyShape
est d'obtenir sa zone.AnyShape
constructeur pour importer l'un des types de forme dans leAnyShape
type.Donc, il s’avère que ce morceau de code ne vous procure pas vraiment quelque chose que ce plus court ne:
Dans le cas de classes multi-méthodes, le même effet peut généralement être obtenu plus simplement en utilisant un codage "enregistrement de méthodes" - au lieu d'utiliser une classe comme
Shape
, vous définissez un type d'enregistrement dont les champs sont les "méthodes" duShape
type , et vous écrivez des fonctions pour convertir vos cercles et carrés enShape
s.Mais cela ne signifie pas que les types existentiels sont un problème! Par exemple, dans Rust, ils ont une fonctionnalité appelée objets de trait que les gens décrivent souvent comme un type existentiel par rapport à un trait (les versions de Rust des classes de types). Si les classes de types existentielles sont un anti-modèle dans Haskell, cela signifie-t-il que Rust a choisi une mauvaise solution? Non! La motivation dans le monde Haskell repose sur la syntaxe et la commodité, pas vraiment sur le principe.
Une façon plus mathématique de formuler ceci est de souligner que les
AnyShape
types d'en hautDouble
sont isomorphes - il existe une "conversion sans perte" entre eux (enfin, sauf pour la précision en virgule flottante):Donc, à proprement parler, vous ne gagnez ou ne perdez aucun pouvoir en choisissant l'un par rapport à l'autre. Ce qui signifie que le choix devrait être basé sur d'autres facteurs tels que la facilité d'utilisation ou les performances.
Et gardez à l'esprit que les types existentiels ont d'autres utilisations en dehors de cet exemple de listes hétérogènes, il est donc bon de les avoir. Par exemple, le
ST
type de Haskell , qui nous permet d'écrire des fonctions purement externes mais qui utilisent des opérations de mutation de mémoire en interne, utilise une technique basée sur des types existentiels afin de garantir la sécurité lors de la compilation.Donc, la réponse générale est qu'il n'y a pas de réponse générale. Les utilisations de types existentiels ne peuvent être jugées que dans le contexte - et les réponses peuvent être différentes selon les caractéristiques et la syntaxe fournies par différentes langues.
la source
Je ne connais pas trop Haskell, je vais donc essayer de répondre à la partie générale de la question en tant que développeur C # fonctionnel et non académique.
Après avoir lu un peu, il s'avère que:
Les caractères génériques Java sont similaires aux types existentiels:
Différence entre les types existentiels de Scala et le caractère générique de Java par exemple
Les caractères génériques ne sont pas implémentés complètement en C #: la variance générique est prise en charge, mais la variance de site d’appel n’est pas:
Génériques C #: Caractères génériques
Vous n’avez peut-être pas besoin de cette fonctionnalité tous les jours, mais quand vous le ferez, vous la sentirez (par exemple, avoir à introduire un type supplémentaire pour que les choses fonctionnent):
Caractères génériques dans les contraintes génériques C #
Sur la base de ces informations, les types existentiels / caractères génériques sont utiles lorsqu'ils sont implémentés correctement et ne présentent aucun problème en eux-mêmes, mais ils peuvent probablement être utilisés de manière abusive, tout comme les autres fonctionnalités du langage.
la source