52 votes

La réalisation de polymorphisme dans la programmation fonctionnelle

Je suis en train de profiter de la transition à partir d'un langage orienté objet à un langage fonctionnel. C'est une bouffée d'air frais, et je suis la recherche de moi-même beaucoup plus productif qu'avant.

Cependant il y a un aspect de la programmation orientée objet que je n'ai pas encore vu une réponse satisfaisante pour le FP, et c'est le polymorphisme. c'est à dire j'ai une grande collection d'éléments de données, qui doivent être traitées de manières très différentes lorsqu'ils sont passés dans certaines fonctions. Pour la clarté de l'exposé, disons qu'il y a plusieurs facteurs qui conduisent à polymorphes comportement potentiellement exponentielle de nombreuses différences de comportement des combinaisons.

Dans la programmation orientée objet qui peut être manipulé relativement bien l'utilisation du polymorphisme: soit au travers de la composition+héritage ou d'un prototype de base de l'approche.

En FP je suis un peu coincé entre:

  • L'écriture ou la composition pure de fonctions permettant de mettre en œuvre polymorphe de comportements par branchement sur la valeur de chaque élément de données - sent un peu comme à l'assemblage d'un énorme conditionnelle ou même en simulant une table de méthode virtuelle!
  • Mettre des fonctions à l'intérieur de la pure structures de données dans un prototype de la mode - ce qui semble comme il fonctionne, mais n'est-ce pas aussi contrevenir à l'idée de définir des fonctions pures séparément à partir de données?

Ce sont recommandées pour les approches fonctionnelles pour ce genre de situation? Il y a des bonnes alternatives?

22voto

mokus Points 2365

Mettre des fonctions à l'intérieur de la pure structures de données dans un prototype de la mode - ce qui semble comme il fonctionne, mais n'est-ce pas aussi contrevenir à l'idée de définir des fonctions pures séparément à partir de données?

Si la répartition de méthode virtuelle est la façon dont vous voulez aborder le problème, c'est parfaitement raisonnable. Comme pour la séparation des fonctions de données, qui est clairement non-fonctionnelle de la notion de commencer avec. Je considère que le principe fondamental de la programmation fonctionnelle être que les fonctions SONT données. Et comme pour votre sentiment que vous êtes en simulant une fonction virtuelle, je dirais que ce n'est pas une simulation à tous. C'EST une fonction virtuelle de la table, et c'est parfaitement OK.

Tout simplement parce que la langue n'est pas de la POO prise en charge intégrée ne signifie pas qu'il n'est pas raisonnable d'appliquer les mêmes principes de conception, il signifie simplement que vous aurez à écrire plus de machines que d'autres langues intégré, parce que vous êtes la lutte contre le naturel de l'esprit de la langue que vous utilisez. Moderne tapé les langages fonctionnels ont de très profond soutien pour le polymorphisme, mais c'est une approche très différente pour le polymorphisme.

Le polymorphisme dans la programmation orientée objet est un peu comme de la "quantification existentielle" dans la logique polymorphe valeur de a QUELQUES de type à l'exécution, mais vous ne savez pas ce que c'est. Dans de nombreux langages de programmation fonctionnelle, le polymorphisme est plus comme "une quantification universelle" - polymorphe valeur peut être instancié à n'IMPORTE quel type de son utilisateur veut. Ils sont les deux faces de la même exacte pièce de monnaie (en particulier, ils changent de place selon si vous êtes à la recherche à une fonction "de l'intérieur" ou "extérieur"), mais il s'avère être extrêmement difficile lors de la conception d'une langue à "faire la pièce juste", en particulier en présence de l'autre langue des fonctionnalités telles que les sous-typage ou plus-kinded polymorphisme (polymorphisme plus de types polymorphes).

Si cela peut aider, vous pouvez vouloir penser polymorphisme dans les langages fonctionnels comme quelque chose de très semblable à la "génériques" en C# ou Java, parce que c'est exactement le type de polymorphisme que, par exemple, ML et Haskell, faveur.

13voto

Lambda Dusk Points 3855

Eh bien, en Haskell, vous pouvez toujours faire un type de classe pour atteindre une sorte de polymorphisme. Fondamentalement, il s'agit de définir des fonctions qui sont traitées pour les différents types. Des exemples sont les classes d' Eq et Show:

data Foo = Bar | Baz

instance Show Foo where
    show Bar = 'bar'
    show Baz = 'baz'

main = putStrLn $ show Bar

La fonction show :: (Show a) => a -> String est défini pour chaque type de données que les instances de la typeclass Show. Le compilateur trouve la bonne fonction pour vous, selon le type.

Cela permet de définir des fonctions de manière plus générale, par exemple:

compare a b = a < b

fonctionne avec n'importe quel type de la typeclass Ord. Ce n'est pas exactement comme la programmation orientée objet, mais vous même peut hériter typeclasses comme suit:

class (Show a) => Combinator a where
    combine :: a -> a -> String

C'est à l'instance pour définir la fonction réelle, vous ne définissez le type similaire à des fonctions virtuelles.

Ce n'est pas complète, et pour autant que je sais, beaucoup de FP langues ne possèdent pas de classes de type. OCaml n'est pas, il pousse qu'au cours de sa programmation orientée objet partie. Et le Système ne dispose pas de tous les types. Mais en Haskell c'est un moyen puissant pour obtenir une sorte de polymorphisme, dans les limites.

Pour aller encore plus loin, les nouvelles extensions de l'2010 standard permettent le type de familles et d'autres choses semblables.

Espérons que cela vous a aidé un peu.

11voto

Doc Brown Points 13438

Qui a dit

la définition des fonctions pures séparément à partir des données

la meilleure pratique?

Si vous voulez polymorphes objets, vous devez les objets. Dans un langage fonctionnel, les objets peuvent être construites par les coller ensemble les "pure data" avec un ensemble de "pur" fonctions d'exploitation de ces données. Cela fonctionne même sans le concept d'une classe. En ce sens, une classe n'est rien, mais un morceau de code qui génère des objets avec le même ensemble d'associés "fonctions pures".

Et polymorphe, les objets sont construits par le remplacement de certaines de ces fonctions d'un objet par les différentes fonctions avec la même signature.

Si vous voulez en savoir plus sur la façon de mettre en œuvre des objets dans un langage fonctionnel (comme le Schéma), ont un coup d'oeil dans ce livre:

Abelson / Sussman: Structure et une Interpration des programmes d'Ordinateur"

4voto

Mike, vos deux approches sont parfaitement acceptables, et les avantages et les inconvénients de chacun sont discutés, de même que Doc Brown dit, dans le Chapitre 2 de SICP. Le premier souffre d'avoir une grande table de type quelque part, qui doit être maintenu. La deuxième est juste traditionnels répartition unique polymorphisme/fonction virtuelle tables.

La raison de ce régime ne dispose pas d'un système intégré, c'est que l'utilisation de la mauvaise objet système pour le problème mène à toutes sortes d'ennuis, donc si vous êtes à la langue designer, lequel choisir? Seul l'envoi de l'héritage simple de ne pas faire face à de multiples facteurs de conduite polymorphes comportement potentiellement exponentielle de nombreuses différences de comportement des combinaisons.'

Pour résument comme suit, il y a de nombreuses manières de construire des objets, et le système de la langue discuté dans SICP, vous donne une boîte à outils de base à partir de laquelle vous pouvez construire celui dont vous avez besoin.

Dans un véritable programme de régime, vous souhaitez construire votre objet système à la main, puis masquer les associés standard avec des macros.

En clojure vous avez réellement un préconstruit objet/système de répartition construit en avec multimethods, et l'un de ses avantages par rapport à l'approche traditionnelle, c'est qu'il peut envoyer sur les types de tous les arguments. Vous pouvez (apparemment) également utiliser la hiérarchie du système pour vous donner l'héritage des caractéristiques semblables, bien que je n'ai jamais utilisé, donc vous devriez prendre cum grano salis.

Mais si vous avez besoin quelque chose de différent de l'objet système choisi par la langue de concepteur, vous pouvez simplement faire une (ou plusieurs) qui convient.

C'est effectivement ce que vous proposez ci-dessus.

Construire ce que vous avez besoin, obtenir tout cela fonctionne, masquer les détails avec des macros.

L'argument entre FP et de l'OO n'est pas de savoir si l'abstraction de données est mauvais, c'est de savoir si l'extraction des données du système est la place pour des trucs de toutes les préoccupations distinctes du programme.

"Je crois qu'un langage de programmation doit permettre de définir de nouveaux types de données. Je ne crois pas qu'un programme doit contenir uniquement des définitions des nouveaux types de données."

1voto

thSoft Points 5513

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