Depuis langage machine (par exemple 0110101000110101
) des langages informatiques ont généralement évolué vers des formes supérieures de l' abstraction est devenue en général plus facile de comprendre le code quand il est appliqué à un problème. Assembleur était une abstraction sur le code machine, C était une abstraction sur Assembleur, etc.
Object-oriented design seems to be very good at allowing us to model a problem in terms of objects, eg, the problem of a university course registration system can be modeled with a Course
class, a Student
class, etc. Then, when we write the solution dans un langage OO, nous avons des classes similaires qui ont des responsabilités et qui sont généralement utiles pour la conception, en particulier pour la modularisation du code. Si je donne ce problème à 10 équipes indépendantes qui le résolvent avec une méthode OO, généralement les 10 solutions auront en commun les classes relatives au problème. Il peut y avoir beaucoup de différences lorsque vous commencez à entrer dans le couplage et les interactions de ces classes, donc il n'y a rien de tel qu'un «écart de représentation zéro».
Mon expérience avec la programmation fonctionnelle est très limitée (pas d'utilisation réelle, seulement des programmes de type Hello World). Je n'arrive pas à voir comment ces langages permettent de mapper facilement les solutions de FP aux problèmes (avec un faible écart de représentation) comme le font les langages OO.
Je comprends les avantages de la PF par rapport à la programmation concurrente. Mais est-ce que je manque quelque chose, ou la PF ne vise-t-elle pas à réduire un écart de représentation (faciliter la compréhension des solutions)?
Une autre façon de se poser la question: le code FP de 10 équipes différentes résolvant le même problème du monde réel aurait-il beaucoup en commun?
Un article de Wikipédia sur l' abstraction (de l'informatique) (mine d'importance):
Les langages de programmation fonctionnels présentent généralement des abstractions liées à des fonctions , telles que les abstractions lambda (transformer un terme en fonction d'une variable), des fonctions d'ordre supérieur (les paramètres sont des fonctions), l' abstraction des crochets (transformer un terme en fonction d'une variable).
L'écart de représentation pourrait être potentiellement accru, car [certains] problèmes du monde réel ne sont pas facilement modélisés avec de telles abstractions.
Une autre façon que je vois décroissant déficit de représentation est en traçant les éléments de solution revenir au problème. Le 0
Se et 1
s en langage machine est très difficile à retracer, alors que la Student
classe est facile à retracer. Toutes les classes d'AO trace facilement à l'espace de problème, mais beaucoup le font.
Les abstractions de PF n'ont-elles pas toujours besoin d'être expliquées pour savoir quelle partie de l'espace à problèmes elles résolvent (à part les problèmes mathématiques )?OK - je suis bon sur cette partie. Après avoir examiné de nombreux autres exemples, je vois comment les abstractions FP sont très claires pour certaines parties du problème exprimées dans le traitement des données.
La réponse acceptée à une question connexe UML peut-il être utilisé pour modéliser un programme fonctionnel? - dit "Les programmeurs fonctionnels n'ont pas beaucoup d'utilisation pour les diagrammes." Je ne me soucie pas si elle est langage UML, mais je me demande sur les abstractions PF étant faciles à comprendre / communiquer, s'il n'y a pas des schémas qui sont largement utilisés ( en supposant que cette réponse est juste). Encore une fois, mon niveau de FP utilisation / compréhension est trivial, donc je comprends pas besoin de schémas sur les programmes de PF simples.
OO Fournisseur de conception a Fonction / classe / package-niveau d'abstraction, avec encapsulation (contrôle d'accès, en se cachant de l'information) à chaque, ce qui rend plus facile gérer la complexité. Ce sont des éléments qui permettent de passer du problème à la solution et vice-versa plus facilement.
De nombreuses réponses parlent de la manière dont l' analyse et la conception se font en FP dans un analogue de manière à OO, personne ne cite rien mais de haut niveau à ce jour (Paul cite des choses intéressantes, mais il est de bas niveau). J'ai fait beaucoup de recherches sur Google hier et trouvé une discussion intéressante. Ce qui suit est extrait de Refactoring Functional Programs de Simon Thompson (2004) (c'est moi qui souligne)
Lors de la conception d'un système orienté objet, il est tenu pour acquis que la conception précédera la programmation. Les conceptions seront écrites à l'aide d'un système comme UML qui est pris en charge dans des outils tels que Eclipse. Les programmeurs débutants pourraient bien apprendre une approche de conception visuelle en utilisant des systèmes comme BlueJ. Œuvre sur une méthodologie similaire pour la programmation fonctionnelle est rapporté dans DCP: Analyse fonctionnelle et conception , guère d' autres tâches existe. Il peut y avoir plusieurs raisons pour cela.
Les programmes fonctionnels existants sont d'une échelle qui ne nécessite pas de conception. De nombreux programmes fonctionnels sont petits, mais d'autres, comme le Glasgow Haskell Compiler, sont importants.
Programmes fonctionnels modélisent directement le domaine d'application, rendant ainsi la conception hors de propos. Alors que les langages fonctionnels offrent une variété d'abstractions puissantes, il est difficile de soutenir que ceux - ci fournissent tous et que les abstractions nécessaires pour modéliser le monde réel.
programmes fonctionnels sont construits comme une série de prototypes en constante évolution.
Dans la thèse citée ci - dessus , les avantages de l' utilisation méthodologies d' analyse et de conception (ADM) sont présentés indépendamment des paradigmes. Mais un argument avancé est que les SMA doivent aligner sur le modèle de mise en œuvre. C'est, OOADM fonctionne le mieux pour la programmation orientée objet et n'est pas bien appliquée à un autre paradigme, comme FP. Voici une citation que je pense paraphrases ce que j'appelle déficit de représentation:
on peut argumenter longuement au sujet de laquelle paradigme offre le meilleur soutien au développement de logiciels, mais on obtient package de développement le plus naturel, efficace et efficace lorsque l'on reste dans un seul paradigme de la description du problème par le biais de mise en œuvre et la livraison.
Voici l'ensemble des schémas proposés par DCP:
- diagrammes de dépendance des fonctions qui présentent une fonction avec ceux qu'il utilise dans sa mise en œuvre;
- la dépendance de type diagramme qui fournit le même service pour les types; et,
- diagrammes de dépendance du module qui présentent des vues de l'architecture du module du système.
Il y a une étude de cas dans la section 5.1 de la thèse FAD, qui est un système pour automatiser la production de données relatives à une ligue de football (soccer). Les exigences sont 100% fonctionnelles, par exemple, saisir les résultats du football, produire des tableaux de ligue, des tableaux de pointage, des tableaux de présence, transférer des joueurs entre les équipes, mettre à jour les données après de nouveaux résultats, etc. Aucune mention du fonctionnement du FAD pour résoudre les exigences non fonctionnelles n'est documentée , en plus de déclarer que "les nouvelles fonctionnalités devraient être autorisées à un coût minime", ce qui est presque impossible à tester.
Malheureusement, en dehors de FAD, je ne vois aucune référence moderne pour les langages de modélisation (visuels) qui sont proposés pour FP. UML est un autre paradigme, nous devons donc l'oublier.
Réponses:
Les données de base sont structurées de la même manière dans pratiquement tous les paradigmes. Vous allez avoir un
Student
, unCourse
, etc., que ce soit un objet, une structure, un enregistrement ou autre. La différence avec la POO n'est pas la façon dont les données sont structurées, c'est la façon dont les fonctions sont structurées.En fait, je trouve que les programmes fonctionnels correspondent beaucoup plus à la façon dont je pense à un problème. Par exemple, pour planifier un calendrier de l'étudiant pour le semestre prochain, vous pensez à des choses comme des listes de cours d'un étudiant a terminé, des cours dans le programme d'études d'un étudiant, les cours offerts ce semestre, les cours d'un étudiant a réussi les préalables nécessaires pour, des cours avec des temps que don « conflit t, etc.
Du coup, on ne sait pas trop quelle classe doit créer et stocker toutes ces listes. Encore moins quand vous avez des combinaisons complexes de ces listes. Cependant, vous devez choisir une classe.
Dans FP, vous écrivez des fonctions qui prennent un étudiant et une liste de cours et renvoyez une liste filtrée de cours. Vous pouvez regrouper toutes ces fonctions ensemble dans un module. Vous n'avez pas à le coupler avec une classe ou une autre.
Ainsi , vos modèles de données finissent par regarder plus comme la façon dont les programmeurs POO pensent de leurs modèles, avant qu'ils ne soient polluées par des classes qui ont pas d' autre but que de fournir des endroits pratiques pour mettre les fonctions qui fonctionnent sur des combinaisons d'autres classes. Pas de
CourseStudentFilterList
classes étranges ou similaires dont vous finissez toujours par avoir besoin dans la POO, mais ne pensez jamais au début du design.la source
StudentCourseFilterer
pour garder les choses à gérerfunc
(comme vous l' avez nomméIFilter
, etc.). En général, dans FP, vous le nommeriezfunc
ouf
lorsque l'unsort
ou oufilter
est un choix valide! Par exemple, lors de l'écriture d'une fonction d'ordre supérieur qui prendfunc
comme paramètre.Quand j'ai pris ma classe Java il y a des années, nous devions montrer nos solutions à toute la classe, alors j'ai pu voir comment les gens pensent; comment ils résolvent les problèmes logiquement. J'attendais les solutions à se regrouper autour de trois ou quatre solutions communes. Au lieu de cela, je l'ai regardé que 30 étudiants ont résolu le problème de 30 façons complètement différentes.
Bien entendu, comme l'expérience naissante de gain de programmeurs, ils gagneront l'exposition à des modèles logiciels courants, commencer à utiliser ces modèles sur leur code, puis leurs solutions peuvent se regrouper autour de quelques stratégies optimales. Ces modèles forment un langage technique par lequel les développeurs expérimentés peuvent communiquer.
Le langage technique qui sous-tend la programmation fonctionnelle est les mathématiques . Par conséquent, les problèmes les plus appropriés pour résoudre en utilisant la programmation fonctionnelle sont essentiellement des problèmes mathématiques. Par mathématiques, je ne fais pas référence au type de mathématiques que vous verriez dans les solutions commerciales, comme l'addition et la soustraction. Au contraire, je parle du genre de mathématiques que vous pouvez voir sur Math Overflow ou le genre de mathématiques que vous verriez dans le moteur de recherche « Orbitz (il est écrit en Lisp).
Cette orientation a des ramifications importantes pour les programmeurs fonctionnels qui tentent de résoudre des problèmes de programmation réels:
La programmation fonctionnelle est plus déclarative qu'impérative; il se préoccupe principalement de dire à l'ordinateur ce qu'il doit faire, pas comment le faire.
Les programmes orientés objet sont souvent construits de haut en bas. Une conception de classe est créée, et les détails sont remplis. Les programmes fonctionnels sont souvent construits à partir du bas vers le haut, en commençant par de petites fonctions détaillées qui sont combinées dans des fonctions de niveau supérieur.
La programmation fonctionnelle peut présenter des avantages pour le prototypage logique complexe, la construction de programmes souples qui peuvent changer et évoluer organiquement, et la construction de logiciels où la conception initiale ne sait pas.
programmes orientés objets peuvent être plus appropriés pour les domaines d'affaires parce que les classes, les messages entre les objets et les modèles de logiciels offrent toutes une structure que les cartes dans le domaine des affaires, capture son intelligence d'affaires et des documents il.
Parce que tous les logiciels pratique produit des effets secondaires (I / O), purement langages de programmation fonctionnels ont besoin d'un mécanisme pour produire ces effets secondaires tout en restant mathématiquement pures (monades).
Les programmes fonctionnels peuvent être plus facilement éprouvés, en raison de leur nature mathématique. Le système de type de Haskell peut trouver des choses au moment de la compilation que la plupart des langages OO ne peuvent pas trouver.
Etc. Comme pour beaucoup de choses en informatique, les langages orientés objet et les langages fonctionnels ont des compromis différents.
Certains langages OO modernes ont adopté certains des concepts de programmation fonctionnelle utiles, afin que vous puissiez avoir le meilleur des deux mondes. Linq, et les fonctionnalités de langage qui ont été ajoutées pour le prendre en charge, en sont un bon exemple.
la source
SafeString
type pour représenter des chaînes qui ont été échappées HTML - et en gardant généralement plus de trace de effets.Je voudrais insister sur un aspect que je trouve important et qui n'a pas été couvert dans les autres réponses.
Tout d'abord, je pense que l'écart de représentation entre les problèmes et les solutions peut être davantage dans l'esprit du programmeur, en fonction de son expérience et des concepts qu'il connaît mieux.
La POO et la FP examinent les données et les opérations sous deux angles différents et fournissent des compromis différents, comme Robert Harvey l'a déjà souligné.
Un aspect important dans lequel ils diffèrent est la manière dont ils permettent d'étendre votre logiciel.
Considérez la situation dans laquelle vous avez une collection de types de données et une collection d'opérations, par exemple vous avez différents formats d'image et vous maintenez une bibliothèque d'algorithmes pour traiter les images.
La programmation fonctionnelle facilite l'ajout de nouvelles opérations à votre logiciel: vous n'avez besoin que d'un changement local dans votre code, à savoir que vous ajoutez une nouvelle fonction, qui gère différents formats de données d'entrée. D'un autre côté, l'ajout de nouveaux formats est plus compliqué: vous devez changer toutes les fonctions que vous avez déjà implémentées (changement non local).
L'approche orientée objet est symétrique à cela: chaque type de données porte sa propre implémentation de toutes les opérations et est chargé de choisir la bonne implémentation lors de l'exécution (répartition dynamique). Cela facilite l'ajout d'un nouveau type de données (par exemple un nouveau format d'image): vous ajoutez simplement une nouvelle classe et implémentez toutes ses méthodes. D'un autre côté, l'ajout d'une nouvelle opération signifie changer toutes les classes qui doivent fournir cette opération. Dans de nombreuses langues, cela se fait en étendant une interface et en adaptant toutes les classes qui l'implémentent.
Cette approche différente à l' extension est l' une des raisons pour lesquelles OOP est plus approprié pour certains problèmes où l'ensemble des opérations varie moins souvent que l'ensemble des types de données sur lesquels de travail ces opérations. Un exemple typique sont des interfaces graphiques: vous disposez d' un ensemble fixe d'opérations que tous les widgets doivent mettre en œuvre (
paint
,resize
,move
et ainsi de suite) et une collection de widgets que vous souhaitez étendre.Ainsi, selon cette dimension, la POO et la FP ne sont que deux façons spéculaires d'organiser votre code. Voir SICP , en particulier la section 2.4.3, le tableau 2.22 et le paragraphe Passage de message .
En résumé: dans la POO, vous utilisez les données pour organiser les opérations, dans FP vous utilisez les opérations pour organiser les données. Chaque approche est plus ou moins forte selon le contexte. En général, aucun des deux n'a un écart de représentation plus élevé entre le problème et la solution.
la source
Other
variante / constructeur dans votre type de données, et un paramètre de fonction supplémentaire à transmettre à toutes les fonctions pour gérer l' autre cas. Il est, bien sûr, maladroit / moins naturel par rapport à la solution POO (dispatch dynamique). De la même façon, le motif de visiteur est gênant / moins naturel que la solution de FP (fonction d'ordre supérieur).La plupart des langages fonctionnels ne sont pas orientés objet. Cela ne veut pas dire qu'ils ne contiennent aucun objet (au sens des types complexes qui ont des fonctionnalités spécifiques qui leur sont associés). Haskell, comme java, a des listes, cartes, groupements, toutes sortes d'arbres et de nombreux autres types complexes. Si vous regardez le module Haskell List ou Map, vous verrez un ensemble de fonctions très similaires aux méthodes de la plupart des modules de bibliothèque de langage OO équivalents. Si vous inspectez le code, vous trouverez même une encapsulation similaire, avec certains types (ou leurs constructeurs, pour être précis) et des fonctions utilisables uniquement par d'autres fonctions du module.
La façon dont vous travaillez avec ces types en Haskell est souvent guère différente de la façon OO. À Haskell, je dis
et en Java vous dites
Tomate, tomate. Les fonctions Haskell ne sont pas liées à l'objet mais elles sont étroitement associées à son type. ¨Ah, mais , ¨ vous dites, ¨ en Java, il appelle quelle méthode de longueur appropriée à la classe réelle de cet objet¨. Surprise - Haskell fait aussi du polymorphisme avec les classes de types (et d'autres choses).
En Haskell, si j'est - une collection d'entiers - peu importe si la collection est une liste ou un ensemble ou un tableau, ce code
retournera une collection avec tous les éléments doublés. Le polymorphisme signifie que la fonction de carte appropriée pour le type spécifique sera appelée.
Ces exemples ne sont en réalité pas des types vraiment complexes, mais il en va de même pour les problèmes plus difficiles. L'idée que les langages fonctionnels ne vous permettent pas de modéliser des objets complexes et de leur associer des fonctionnalités spécifiques est tout simplement fausse.
Il existe des différences importantes et significatives entre le style fonctionnel et le style OO, mais je ne pense pas que cette réponse doive y faire face. Vous avez demandé si les langages fonctionnels empêchent (ou entravent) la modélisation intuitive des problèmes et des tâches. La réponse est non.
la source
FP s'efforce en effet de réduire l'écart de représentation:
Quelque chose que vous verrez beaucoup dans les langages fonctionnels est la pratique de construire le langage (en utilisant une conception ascendante) dans un langage spécifique au domaine intégré (EDSL) . Cela vous permet de développer un moyen d'exprimer vos préoccupations commerciales d'une manière naturelle pour votre domaine dans le langage de programmation. Haskell et Lisp en sont fiers.
Une partie (sinon la totalité) de ce qui permet cette capacité est une plus grande flexibilité et expressivité dans la ou les langues de base elles-mêmes; avec les fonctions de première classe, les fonctions d'ordre supérieur, la composition des fonctions et, dans certains langages, les types de données algébriques (unions discriminées AKA) et la capacité de définir des opérateurs *, il y a plus de flexibilité disponible pour exprimer des choses qu'avec OOP, qui signifie que vous trouverez probablement des moyens plus naturels d'exprimer les choses de votre domaine problématique. (Cela devrait dire quelque chose que de nombreux langages OOP ont adopté bon nombre de ces fonctionnalités récemment, sinon en commençant par eux.)
* Oui, dans de nombreux langages OOP, vous pouvez remplacer les opérateurs standard, mais dans Haskell, vous pouvez en définir de nouveaux!
Dans mon expérience de travail avec les langages fonctionnels (principalement F # et Haskell, certains Clojure, et un peu Lisp et Erlang), j'ai plus de facilité à cartographier l'espace des problèmes dans le langage qu'avec OOP - en particulier avec les types de données algébriques, que je trouve plus flexible que les cours. Quelque chose qui m'a mis en boucle lors du démarrage avec FP, en particulier avec Haskell, était que je devais penser / travailler à un niveau un peu plus élevé que celui auquel j'étais habitué dans les langages impératifs ou OOP; vous pourriez également être un peu confronté à cela.
la source
Comme Niklaus Wirth l'a dit, "Algorithmes + Structures de Données = Programmes". La programmation fonctionnelle concerne la façon d'organiser les algorithmes, et elle ne dit pas grand-chose sur les façons d'organiser les structures de données. En effet, il existe des langages FP à la fois avec des variables mutables (Lisp) et immuables (Haskell, Erlang). Si vous voulez comparer et contraster FP avec quelque chose, vous devez choisir une programmation impérative (C, Java) et déclarative (Prolog).
La POO est d'autre part un moyen de construire des structures de données et d'y attacher des algorithmes. FP ne vous empêche pas de construire des structures de données similaires à celles de la POO. Si vous ne me croyez pas, jetez un œil aux déclarations de type Haskell. Cependant, la plupart des langages FP conviennent que les fonctions n'appartiennent pas aux structures de données et devraient plutôt se trouver dans le même espace de noms. Ceci est fait afin de simplifier la construction de nouveaux algorithmes via la composition des fonctions. En effet, si vous savez quelle entrée prend une fonction et quelle sortie elle produit, pourquoi importe-t-elle également à quelle structure de données elle appartient? Par exemple, pourquoi la
add
fonction doit-elle être appelée sur une instance de type Integer et passée un argument au lieu de simplement passer deux arguments Integer?Par conséquent, je ne vois pas pourquoi FP devrait rendre les solutions plus difficiles à comprendre en général, et je ne pense pas que ce soit le cas de toute façon. Cependant, gardez à l'esprit qu'un programmeur chevronné et impératif trouvera certainement les programmes fonctionnels plus difficiles à comprendre que les impératifs, et vice versa. Ceci est similaire à la dichotomie Windows - Linux lorsque les gens qui ont investi 10 ans pour se familiariser avec l'environnement Windows trouvent Linux difficile après un mois d'utilisation, et ceux qui sont habitués à Linux ne peuvent pas atteindre la même productivité sous Windows. Par conséquent, le «fossé de représentation» dont vous parlez est très subjectif.
la source
if you know what input a function takes and what output it produces, why should it matter which data structure it belongs too?
Cela ressemble beaucoup à de la cohésion, ce qui est important pour tout système modulaire. Je dirais que ne pas savoir où trouver une fonction rendrait plus difficile la compréhension d'une solution, ce qui est dû à un écart de représentation plus élevé. Beaucoup de systèmes OO ont ce problème, mais c'est à cause d'une mauvaise conception (faible cohésion). Encore une fois, le problème de l'espace de noms est hors de mon expertise en FP, donc ce n'est peut-être pas aussi grave qu'il y paraît.