T-programmation fonctionnelle augmenter le « déficit de représentation » entre les problèmes et solutions? [fermé]

18

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 Courseclass, a Studentclass, 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 0Se et 1s en langage machine est très difficile à retracer, alors que la Studentclasse 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.

Fuhrmanator
la source
1
Les commentaires ne sont pas pour une discussion approfondie; cette conversation a été déplacée vers le chat .
maple_shaft

Réponses:

20

Les données de base sont structurées de la même manière dans pratiquement tous les paradigmes. Vous allez avoir un Student, un Course, 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 CourseStudentFilterListclasses étranges ou similaires dont vous finissez toujours par avoir besoin dans la POO, mais ne pensez jamais au début du design.

Karl Bielefeldt
la source
5
@BenAaronson le problème dans mon expérience est que alors toute fonction liée à un étudiant est ajouté à la classe des élèves et de ses responsabilités grandir et grandir jusqu'à ce que vous devez introduire StudentCourseFiltererpour garder les choses à gérer
AlexFoxGill
3
@Den approches hybrides ont leurs mérites. Il est pas vrai, cependant, que la distinction est artificielle. Il y a beaucoup de compromis que Scala a dû faire pour adapter OOP et FP (l'inférence de type moins puissante en est une. La complexité en est une autre: oui, un langage qui mélange OOP et FP a tendance à être plus complexe - comme dans "difficile à utiliser" et comprendre » - que l' un de ses plus purs frères sur les deux extrêmes).
Andres F.
3
@Den Voir aussi Erik Meijer « Programmation « La plupart du temps fonctionnel » ne fonctionne pas » , ce qui va à l' encontre de l'approche hybride et pour aller « fondamentaliste » complète FP.
Andres F.
4
@Den La popularité que vous décrivez est, je le crains, un accident de l'histoire. J'utilise Scala au travail, et c'est une bête complexe en raison de la façon dont elle tente de mélanger FP et OOP. Le passage à un véritable langage de FP comme Haskell se sent comme une bouffée d'air frais - et je ne parle pas du point de vue académique non plus !
Andres F.
3
@Den Je ne peux pas dire ce que l' une de ces fonctions faire. Cependant, je peux vous dire si la première fonction de PF était une sorte ou un filtre, il serait nommé filtre ou de tri , pas func(comme vous l' avez nommé IFilter, etc.). En général, dans FP, vous le nommeriez funcou florsque l'un sortou ou filterest un choix valide! Par exemple, lors de l'écriture d'une fonction d'ordre supérieur qui prend funccomme paramètre.
Andres F.
10

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:

  1. 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.

  2. 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.

  3. 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.

  4. 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.

  5. 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).

  6. 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.

Robert Harvey
la source
6
@thepacker: Vous avez un état dans la programmation fonctionnelle. Seule la représentation est différente: en POO vous utilisez des variables mutables alors que dans la programmation fonctionnelle , vous pouvez utiliser les flux infini d'états qui sont créés à la volée lorsque le programme a besoin de les inspecter. Malheureusement, l'état est souvent identifié avec des variables mutables, comme si les variables mutables étaient le seul moyen de représenter l'état. En conséquence, beaucoup pensent qu'un langage de programmation sans variables mutables ne peut pas modéliser l'état.
Giorgio
12
"En conséquence, les problèmes les plus appropriés pour résoudre en utilisant la programmation fonctionnelle sont essentiellement des problèmes mathématiques.": Je ne suis pas d'accord avec cette affirmation (voir aussi mon commentaire précédent), du moins je ne vois pas pourquoi elle devrait être vraie ou ce qu'elle signifie en fait. Vous pouvez voir traverser une structure de répertoires comme un problème mathématique et l'implémenter avec une fonction récursive, mais comme le client ne voit pas le code source, vous résolvez simplement un problème pratique comme trouver un fichier quelque part dans le système de fichiers. Je trouve distinction entre un mathématiques et des problèmes non-mathématiques artificielle.
Giorgio
5
+1, mais je ne suis pas vendu sur les points 2 et 4. J'ai vu de nombreux tutoriels et articles de blog Haskell qui commencent par s'attaquer à un problème de haut en bas, définissant tous les types et opérations pour voir comment tout s'emboîte laissant toutes les définitions de valeur et fonction non définie (bien définie pour lancer une exception). Il me semble que les programmeurs Haskell ont tendance à modéliser le problème de manière plus approfondie car ils sont plus enclins à ajouter des types triviaux pour des raisons de sémantique - par exemple, en ajoutant un SafeStringtype pour représenter des chaînes qui ont été échappées HTML - et en gardant généralement plus de trace de effets.
Doval
4
« les problèmes qui sont les plus appropriés pour résoudre en utilisant la programmation fonctionnelle sont essentiellement des problèmes de mathématiques. » C'est tout simplement pas vrai. Le fait que le concept de Monades provienne de la théorie des catégories ne signifie pas non plus que les tâches mathématiques sont le domaine le plus naturel / adapté aux langages fonctionnels. Tout cela signifie que le code écrit dans des langages fonctionnels fortement typés peut être décrit, analysé et raisonné sur l'utilisation des mathématiques. Ceci est une fonctionnalité supplémentaire puissante, pas quelque chose qui vous empêche d'écrire "Barbie Horse Adventures" dans Haskell.
itsbruce
6
@itsbruce Barbie Horse Adventures est une simulation mathématique sérieuse du plus haut calibre, c'est pidgeon holing FP en projections numériques trop complexes comme des matrices décrivant le scintillement physique des cheveux de Barbie sur une période discrète dans une variété d'environnements du monde réel possibles qui convainc les gens de complètement rejeter comme non pertinents à leur problème d'affaires tous les jours de codage.
Jimmy Hoffa
7

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, moveet 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.

Giorgio
la source
1
En fait, Visitor Pattern (dans OOP) vous donne le même pouvoir que vous avez dit pour FP. Il vous permet d'ajouter de nouvelles opérations tout en rendant plus difficile l'ajout de nouvelles classes. Je me demande si vous pouvez faire de même en FP (par exemple en ajoutant de nouveaux formats au lieu d'opérations).
Euphoric
1
Le scénario de traitement d'image ne semble pas être le meilleur exemple. Certes , vous souhaitez convertir les images dans un format interne et processus au lieu d'écrire des implémentations différentes de tous vos trucs de traitement d'image pour chaque type d'image?
Hey
1
@Giorgio peut-être que je n'obtiens pas le sens voulu de cette partie: "l'ajout de nouveaux formats est plus impliqué: vous devez changer toutes les fonctions que vous avez déjà implémentées."
Hey
2
@Hey Giorgio est probablement référence à la soi-disant problème d'expression . « L' ajout de nouveaux formats » signifie « l' ajout de nouveaux constructeurs (alias « cas ») à un type de données ».
Andres F.
1
@Euphoric: Je ne l' ai pas regardé dans les détails, mais la contrepartie de FP au modèle des visiteurs devrait impliquer une Othervariante / 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).
Giorgio
5

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

  null xs
  length xs

et en Java vous dites

  xs.isEmpty
  xs.length

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

  fmap (* 2) is

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.

itsbruce
la source
En fait, vous pouvez utiliser des classes de types en Java / C #; vous venez de passer explicitement le dictionnaire des fonctions, au lieu d'avoir le compilateur déduire la bonne en fonction du type.
Doval
Oh, définitivement. Comme l'a dit William Cook, une grande partie du code OO utilise en fait plus fréquemment des fonctions d'ordre supérieur que le code fonctionnel, même si le codeur n'en est probablement pas conscient.
itsbruce
2
Vous faites une fausse distinction. Une liste n'est pas plus une structure de données inerte qu'une pile ou une file d'attente ou un simulateur tic-tac-toe. Une liste peut contenir n'importe quoi (dans Haskell, il pourrait bien s'agir de fonctions partiellement appliquées) et définit comment ces choses peuvent interagir avec. Vous pouvez appliquer une liste remplie de fonctions partiellement appliquées à une autre liste de valeurs et le résultat serait une nouvelle liste contenant toutes les combinaisons possibles de fonctions de la première et entrées de la seconde. C'est bien plus qu'une structure C.
itsbruce
3
Les types sont utilisés pour des choses plus variées dans les langages fonctionnels que ceux impératifs / OO (les systèmes de types ont tendance à être plus puissants et cohérents, d'une part). Les types et leurs fonctions sont utilisés pour façonner les chemins de code (c'est pourquoi plusieurs langages fonctionnels n'ont tout simplement pas de mots-clés pour les boucles - pas nécessaires), par exemple.
itsbruce
4
@Fuhrmanator "Je ne vois pas comment cela se fait dans FP" Donc vous vous plaignez de quelque chose que vous ne comprenez pas n'a pas de sens; allez l'apprendre, le comprendre à fond, et alors ça aura du sens. Peut-être qu'après que cela aura du sens, vous déciderez que c'est de la merde et que vous n'avez pas besoin que d'autres vous le prouvent, bien que d'autres personnes comme ci-dessus le comprennent et ne soient pas parvenues à cette conclusion. Vous semblez avoir apporté un couteau à une fusillade, et maintenant vous dites à tout le monde que les armes à feu sont inutiles parce qu'elles ne sont pas tranchantes.
Jimmy Hoffa du
4

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.

Paul
la source
Les préoccupations commerciales (du client) ne sont pas exprimées très souvent dans des fonctions d'ordre supérieur. Mais un client peut écrire une histoire d'utilisateur sur une seule ligne et vous fournir des règles commerciales (ou vous pouvez les retirer du client). Je suis intéressé par la modélisation de domaine (de haut en bas?) (À partir de ces artefacts) qui nous permet d'arriver à des abstractions du problème qui correspondent à des fonctions de première classe, etc. Pouvez-vous citer quelques références? Pouvez-vous utiliser un exemple concret d'un domaine, les abstractions, etc.?
Fuhrmanator
3
@Fuhrmanator Un client peut toujours écrire des user stories et des règles métier sur une seule ligne, que vous utilisiez OOP et FP . Je ne m'attends pas à ce que les clients comprennent les fonctions d'ordre supérieur pas plus que je ne m'attends à ce qu'ils comprennent l'héritage, la composition ou les interfaces.
Andres F.
1
@Fuhrmanator À quelle fréquence avez-vous demandé au client d'exprimer ses préoccupations en termes de génériques Java ou de classes de base abstraites et d'interfaces? Cher Dieu. Paul vous a donné une très bonne réponse, expliquant une méthode pratique et fiable de modélisation utilisant des techniques sûrement pas trop difficiles à visualiser. Et pourtant, vous insistez pour qu'il soit décrit en termes d'une technique de modélisation spécifique pour un paradigme particulier, comme si c'était en quelque sorte la manière la plus naturelle de représenter le design et tout le reste peut être redessiné dans ses termes.
itsbruce
@Fuhrmanator Ce n'est peut-être pas aussi élevé que vous le recherchez, mais devrait donner un aperçu du processus de conception à l'aide de techniques fonctionnelles: Conception avec types . Je recommanderais de parcourir ce site en général car il contient d'excellents articles.
Paul
@Fuhrmanator Il y a aussi cette série Thinking Functionally
paul
3

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 addfonction 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.

mkalkov
la source
En raison de l'encapsulation et du masquage des données, qui ne sont pas des principes OO en soi, je ne suis pas entièrement d'accord avec le fait que OO soit des structures de données + des algorithmes (c'est la vue interne uniquement). La beauté de toute bonne abstraction est qu'il offre un service pour résoudre une partie du problème, sans que l'on ait besoin de comprendre trop de détails. Je pense que vous parlez d'encapsulation lorsque vous séparez des fonctions et des données dans FP, mais je suis trop vert pour en être sûr. En outre, j'ai modifié ma question pour faire référence au traçage de la solution au problème (pour clarifier la signification de l'écart de représentation).
Fuhrmanator
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.
Fuhrmanator
1
@Fuhrmanator Mais vous ne savez où trouver une fonction. Et il n'y a qu'une seule fonction, pas plusieurs fonctions du même nom, définie pour chaque type de données (encore une fois, voir le "problème d'expression"). Par exemple, pour les fonctions de la bibliothèque Haskell (que vous êtes encouragé à utiliser, au lieu de redécouvrir la roue ou de créer des versions légèrement moins utiles desdites fonctions), vous disposez de merveilleux outils de découverte tels que Hoogle , qui est si puissant qu'il vous permet de rechercher par signature (essayez-le! :))
Andres F.
1
@ Fuhrmanator, après "Cela ressemble beaucoup à de la cohésion", je m'attendais à ce que vous concluriez logiquement que les langages FP vous permettent d'écrire des programmes avec une cohésion plus élevée mais vous m'avez surpris. :-) Je pense que vous devriez choisir une langue FP, l'apprendre et décider par vous-même. Si j'étais vous, je suggère de commencer par Haskell car il est assez pur et ne vous permettra donc pas d'écrire du code de façon impérative. Erlang et certains Lisp sont également de bons choix, mais ils se mélangent dans d'autres styles de programmation. Scala et Clojure, OMI, sont assez compliqués pour commencer.
mkalkov