La programmation fonctionnelle ignore-t-elle les avantages tirés des «Sur les critères à utiliser pour décomposer les systèmes en modules» (masquage des données)?

27

Il y a un article classique intitulé Sur les critères à utiliser dans la décomposition des systèmes en modules que je viens de lire pour la première fois. Cela est parfaitement logique pour moi et est probablement l'un de ces articles sur lesquels la POO était basée. Sa conclusion:

Nous avons essayé de démontrer par ces exemples qu'il est presque toujours incorrect de commencer la décomposition d'un système en modules sur la base d'un organigramme. ... Chaque module est alors conçu pour cacher une telle décision aux autres

À mon avis, sans instruction et sans expérience, la programmation fonctionnelle suit exactement le contraire de cet article. Ma compréhension est que la programmation fonctionnelle rend le flux de données idiomatique. Les données sont transmises de fonction en fonction, chaque fonction étant intimement consciente des données et les "modifiant" en cours de route. Et je pense avoir vu un discours de Rich Hickey où il parle de la façon dont le masquage des données est surfait ou inutile ou quelque chose, mais je ne m'en souviens pas avec certitude.

  1. Je veux d'abord savoir si mon évaluation est correcte. Le paradigme de la PF et cet article sont-ils philosophiquement en désaccord?
  2. En supposant qu'ils ne sont pas d'accord, comment FP "compense" -il le manque de données cachées? Peut-être sacrifient-ils le masquage des données mais gagnent-ils X, Y et Z. J'aimerais savoir pourquoi X, Y et Z sont considérés comme plus avantageux que le masquage des données.
  3. Ou, en supposant qu'ils ne sont pas d'accord, FP pense peut-être que le masquage des données est mauvais. Si oui, pourquoi pense-t-il que le masquage des données est mauvais?
  4. En supposant qu'ils soient d'accord, j'aimerais savoir ce qu'est la mise en œuvre par les FP de la dissimulation des données. Il est évident de voir cela dans OOP. Vous pouvez avoir un privatechamp auquel personne en dehors de la classe ne peut accéder. Il n'y a pas d'analogie évidente avec cela dans FP.
  5. Je pense qu'il y a d'autres questions que je devrais poser, mais je ne sais pas que je devrais poser. N'hésitez pas à y répondre également.

Mise à jour

J'ai trouvé cet exposé de Neal Ford qui contient une diapositive très pertinente. Je vais intégrer la capture d'écran ici:

entrez la description de l'image ici

Daniel Kaplan
la source
1
Je ne peux pas répondre à la question complète, mais comme pour (4), il existe des systèmes de modules dans certains langages FP qui peuvent fournir l'encapsulation.
Andres F.
@AndresF. ah ouais c'est vrai. J'ai oublié que Haskell a des modules et vous pouvez y cacher des types de données et des fonctions. Peut-être que quand je dis FP, je dis vraiment Clojure. Vous pouvez avoir des fonctions privées et des "champs" dans Clojure, mais j'ai l'impression que c'est idiomatique de rendre vos données visibles à tout et de les transmettre n'importe où.
Daniel Kaplan
6
Ce que vous faites souvent, c'est rendre vos types visibles, mais cachez vos constructeurs. Ces types abstraits sont particulièrement bien faits par le système de modules OCaml
Daniel Gratzer
6
Dans un langage de type ML, le fait de ne pas avoir accès aux constructeurs signifie que vous ne pouvez pas appliquer de correspondance de motif sur une valeur de ce type pour la déconstruire. La seule chose que vous pouvez faire avec ces valeurs est de la transmettre à la fonction mise à disposition. C'est le même type d'abstraction de données que dans D, disons, qui n'a pas non plus de notions de premier plan sur ce qui est public ou privé.
Luc Danton
1
@ SK-logic: Du point de vue d'un "problème d'expression", révéler les données est bon lorsque vous souhaitez étendre avec de nouvelles fonctions à l'avenir (et êtes d'accord pour garder les données fixes) et masquer les données est bon quand vous voulez à étendre avec de nouveaux types de données à l'avenir (au prix de maintenir l'interface fonctionnelle fixe)
hugomg

Réponses:

23

L'article que vous mentionnez concerne la modularité en général et s'appliquerait également aux programmes structurés, fonctionnels et orientés objet. J'ai déjà entendu parler de cet article par quelqu'un qui était un grand gars de la POO, mais je l'ai lu comme un article sur la programmation en général, pas quelque chose de spécifique à la POO. Il y a un article célèbre sur la programmation fonctionnelle, Why Functional Programming Matters , et la première phrase de la conclusion déclare "Dans cet article, nous avons soutenu que la modularité est la clé d'une programmation réussie." La réponse à (1) est donc non.

Les fonctions bien conçues n'assument pas plus sur leurs données que nécessaire, donc la partie sur "intimement consciente des données" est fausse. (Ou au moins aussi faux que cela pourrait être de la POO. Vous ne pouvez pas programmer strictement à un niveau d'abstraction élevé et ignorer tous les détails pour toujours dans n'importe quel paradigme. En fin de compte, une partie du programme doit réellement connaître la détails spécifiques des données.)

Le masquage des données est un terme spécifique à la POO, et il n'est pas exactement le même que le masquage des informations discuté dans l'article. Les informations qui se cachent dans l'article concernent des décisions de conception difficiles à prendre ou susceptibles de changer. Toutes les décisions de conception concernant un format de données ne sont pas difficiles ou susceptibles de changer, et toutes les décisions difficiles ou susceptibles de changer ne concernent pas un format de données. Personnellement, je ne vois pas pourquoi les programmeurs OO veulent que tout soit un objet. Parfois, une simple structure de données suffit.

Edit: J'ai trouvé une citation pertinente d' une interview avec Rich Hickey .

Fogus: Suite à cette idée, certaines personnes sont surprises par le fait que Clojure ne s'engage pas dans l'encapsulation de masquage de données sur ses types. Pourquoi avez-vous décidé de renoncer à la dissimulation de données?

Hickey: Soyons clairs, Clojure met fortement l'accent sur la programmation des abstractions. À un moment donné cependant, quelqu'un devra avoir accès aux données. Et si vous avez une notion de «privé», vous avez besoin des notions correspondantes de privilège et de confiance. Et cela ajoute une tonne de complexité et peu de valeur, crée de la rigidité dans un système et oblige souvent les choses à vivre dans des endroits où elles ne devraient pas. Ceci s'ajoute à l'autre perte qui se produit lorsque de simples informations sont mises dans les classes. Dans la mesure où les données sont immuables, il y a peu de mal à fournir l'accès, à part le fait que quelqu'un pourrait en venir à dépendre de quelque chose qui pourrait changer. Bon, d'accord, les gens font ça tout le temps dans la vraie vie, et quand les choses changent, ils s'adaptent. Et s'ils sont rationnels, ils savent quand ils prennent une décision basée sur quelque chose qui peut changer qu'ils pourraient à l'avenir devoir s'adapter. C'est donc une décision de gestion des risques, une décision que les programmeurs devraient être libres de prendre. Si les gens n'ont pas la sensibilité de vouloir programmer des abstractions et de se méfier des détails d'implémentation, alors ils ne seront jamais de bons programmeurs.

Michael Shaw
la source
2
Les programmeurs OO ne veulent pas que tout soit un objet. Mais certaines choses (beaucoup de choses) bénéficient de l'encapsulation. J'ai du mal à comprendre comment ou où votre réponse répond vraiment à la question. Il semble simplement affirmer que le concept n'est pas spécifique à la POO et que la POO a d'autres problèmes, etc. - pouvez-vous peut-être fournir un exemple clair, même s'il ne s'agit que de quelques lignes de pseudocode? Ou une description du tableau blanc d'un design qui en tient compte? Ou quelque chose qui pourrait étayer les affirmations ici?
Aaronaught
2
@Aaronaught: J'ai abordé de nombreux (mais pas tous) les points soulevés dans la question et référencé un article sur la programmation fonctionnelle qui examine la modularité d'une manière similaire à l'article de la question. Dans une large mesure, le fait que le concept ne soit pas spécifique à la POO est la réponse à sa question (sauf si j'ai mal compris la question). Je n'ai vraiment pas parlé de la POO ayant d'autres problèmes ici. Vous avez un bon point à fournir un exemple; Je vais voir si je peux en trouver un bon.
Michael Shaw du
2
"Parfois, une simple structure de données suffit." +1. Quelque chose OOP a du sens, parfois c'est FP.
Laurent Bourgault-Roy
1
@Aaronaught Cette réponse souligne que la modularité (qui est à la fois l'encapsulation et la réutilisation) est l'un des objectifs de la PF (comme expliqué dans "Pourquoi la programmation fonctionnelle est importante"), rendant ainsi la réponse au point (1) de la question un " non".
Andres F.
2
La dissimulation d'informations @JimmyHoffa est un principe sensé même en dehors d'OO. Dans haskell, je veux toujours que les utilisateurs soient autorisés à travailler avec un minimum de connaissances sur n'importe quelle structure de données. Bien sûr, avoir accès aux internes est moins dangereux car rien n'est mutable. Mais moins un utilisateur voit un module / une structure de données / un concept abstrait, plus vous obtenez d'opportunités de refactoring. Je fais donc attention si une carte est un arbre binaire équilibré ou une souris dans une petite boîte dans mon ordinateur. C'est la principale motivation derrière le masquage des données, et elle est valable en dehors d'OO.
Simon Bergot
12

... et est probablement l'un de ces articles sur lesquels la POO était basée.

Pas vraiment, mais cela a ajouté à la discussion, spécialement aux praticiens qui, à l'époque, étaient formés pour décomposer les systèmes en utilisant les premiers critères qu'il décrit dans l'article.

Je veux d'abord savoir si mon évaluation est correcte. Le paradigme de la PF et cet article sont-ils philosophiquement en désaccord?

De plus, à mes yeux, votre description de ce à quoi ressemble un programme de PF n'est pas différente de toute autre qui utilise des procédures ou des fonctions:

Les données sont transmises de fonction en fonction, chaque fonction étant intimement consciente des données et les "modifiant" en cours de route.

... sauf pour la partie "intimité", puisque vous pouvez (et avez souvent) des fonctions fonctionnant sur des données abstraites, précisément pour éviter l'intimité. Ainsi, vous avez un certain contrôle sur cette «intimité» et vous pouvez la réguler comme bon vous semble, en configurant des interfaces (c'est-à-dire des fonctions) pour ce que vous voulez cacher.

Donc, je ne vois aucune raison pour laquelle nous ne serions pas en mesure de suivre les critères Parnas de dissimulation d'informations à l'aide de la programmation fonctionnelle et de nous retrouver avec une implémentation d'un index KWIC avec des avantages pointus similaires à sa deuxième implémentation.

En supposant qu'ils soient d'accord, j'aimerais savoir ce qu'est la mise en œuvre par les FP de la dissimulation des données. Il est évident de voir cela dans OOP. Vous pouvez avoir un champ privé auquel personne en dehors de la classe ne peut accéder. Il n'y a pas d'analogie évidente avec cela dans FP.

En ce qui concerne les données, vous pouvez élaborer des abstractions de données et des abstractions de types de données à l'aide de FP. N'importe laquelle de ces structures cache des structures en béton et des manipulations de ces structures en béton en utilisant des fonctions comme abstractions.

MODIFIER

Il y a un nombre croissant d'affirmations ici affirmant que «cacher des données» dans le contexte de la PF n'est pas si utile (ou OOP-ish (?)). Alors, laissez-moi tamponner ici un exemple très simple et clair du SICP:

Supposons que votre système doive fonctionner avec des nombres rationnels. Vous pouvez éventuellement les représenter sous la forme d'une paire ou d'une liste de deux nombres entiers: le numérateur et le dénominateur. Ainsi:

(define my-rat (cons 1 2)) ; here is my 1/2 

Si vous ignorez l'abstraction des données, vous obtiendrez très probablement le numérateur et le dénominateur en utilisant caret cdr:

(... (car my-rat)) ; do something with the numerator

En suivant cette approche, toutes les parties du système qui manipulent des nombres rationnels sauront qu'un nombre rationnel est un cons- ils consnuméroteront pour créer des rationnels et les extraire en utilisant des opérateurs de liste.

Un problème auquel vous pouvez être confronté est lorsque vous devez avoir une forme réduite de nombres rationnels - des changements seront nécessaires dans l'ensemble du système. De plus, si vous décidez de réduire au moment de la création, vous constaterez peut-être plus tard que la réduction lors de l'accès à l'un des termes rationnels est meilleure, ce qui entraînera un autre changement à grande échelle.

Un autre problème est si, hypothétiquement, une représentation alternative pour eux est préférée et que vous décidez d'abandonner la consreprésentation - changement à grande échelle à nouveau.

Tout effort raisonnable pour faire face à ces situations commencera probablement à cacher la représentation des logiques derrière les interfaces. À la fin, vous pourriez vous retrouver avec quelque chose comme ceci:

  • (make-rat <n> <d>)renvoie le nombre rationnel dont le numérateur est l'entier <n>et dont le dénominateur est l'entier <d>.

  • (numer <x>)renvoie le numérateur du nombre rationnel <x>.

  • (denom <x>)renvoie le dénominateur du nombre rationnel <x>.

et le système ne saura plus (et ne devrait plus) savoir de quoi sont faites les justifications. C'est parce que cons, caret cdrne sont pas intrinsèques aux rationnels, mais make-rat, numeret le denom sont . Bien sûr, cela pourrait facilement être un système de PF. Ainsi, la "dissimulation de données" (dans ce cas, mieux connue sous le nom d'abstraction de données, ou l'effort d'encapsuler des représentations et des structures concrètes) se présente comme un concept pertinent et une technique largement utilisée et explorée, que ce soit dans le contexte de l'OO, de la programmation fonctionnelle ou peu importe.

Et le fait est ... bien que l'on puisse essayer de faire des distinctions entre le "type de dissimulation" ou l'encapsulation qu'ils font (qu'ils cachent une décision de conception, ou des structures de données ou des algorithmes - dans le cas d'abstractions procédurales), tous ont le même thème: ils sont motivés par un ou plusieurs points explicités par Parnas. C'est:

  • Changeabilité: si les modifications requises peuvent être apportées localement ou réparties dans le système.
  • Développement indépendant: dans quelle mesure deux parties du système peuvent être développées en parallèle.
  • Compréhension: quelle partie du système doit être connue pour comprendre l'une de ses parties.

L'exemple ci-dessus a été tiré du livre SICP donc, pour la discussion complète et la présentation de ces concepts dans le livre, je recommande fortement de consulter le chapitre 2 . Je recommande également de se familiariser avec les types de données abstraits dans le contexte de la FP, ce qui apporte d'autres problèmes à la table.

Thiago Silva
la source
J'accepte que la dissimulation des données soit pertinente dans FP. Et, comme vous le dites, il existe des moyens d'y parvenir.
Andres F.
2
Vous venez de faire mon point magnifiquement: vous avez ces fonctions qui ne cachent pas les données, ce sont des expressions qui décrivent comment obtenir des données, donc en ayant l'abstraction dans une expression plutôt qu'un champ de données, vous n'avez pas à vous soucier de cacher les données en créant un objet complexe avec des membres privés ou en rendant vos contre-valeurs inaccessibles, les activités de génération, de récupération et d'interaction avec des données rationnelles sont exprimées, donc les données rationnelles réelles n'ont pas besoin d'être cachées car la modification des données ne le sera pas changez vos expressions.
Jimmy Hoffa
8

Votre conviction que la programmation fonctionnelle manque de masquage des données est fausse. Il faut simplement une approche différente pour masquer les données. L'un des moyens les plus courants de masquer des données dans la programmation fonctionnelle consiste à utiliser des fonctions polymorphes qui prennent une fonction comme argument. Par exemple, cette fonction

map :: (a -> b) -> [a] -> [b]
map _ [] = []
map f (x:xs) = f x : map f xs

ne peut voir que la structure la plus externe des données (c'est-à-dire qu'il s'agit d'une liste), il ne peut rien voir des données que la liste contient et ne peut opérer sur les données que via la fonction unique qui lui est transmise.

La fonction passée en argument est analogue à une méthode publique sur le type de données que contient la liste. Il fournit un moyen limité d'opérer sur les données, mais n'expose pas le fonctionnement interne du type de données.

Dirk Holsopple
la source
5

Je vais me lancer sur une branche ici et dire que le concept n'est tout simplement pas pertinent en PF comme il l'est en OO.

tl; dr; Le but de la dissimulation des données est de s'assurer que les responsabilités sont maintenues là où elles devraient être, et que vous n'avez pas d'acteurs extérieurs jouant avec des données pour lesquelles ils n'ont pas les connaissances. Dans FP, les données sont générées par des expressions, et de cette façon, vous ne pouvez pas jouer avec les données car ce ne sont pas autant des propriétés mutables que des calculs composables qui changent complètement les règles du jeu.


Dans mes expériences avec FP; qui sont certes insignifiantes, j'ai tendance à trouver un contraste frappant avec OO dans ce qui dénote une bonne / commune modélisation des données.

Ce contraste est qu'en OO en général, vous modélisez des choses pour représenter vos données. Analogie obligatoire avec la voiture:

OO

  • Vous avez un objet de voiture, qui cache correctement les détails de la voiture tels que la mise en œuvre AC (est-il entraîné par courroie ou entraîné par la pression atmosphérique? Les consommateurs ne devraient pas avoir besoin de le savoir, alors cachez-le).
  • Cet objet de voiture a de nombreuses propriétés et méthodes qui délimitent tous les faits sur la voiture ainsi que les façons dont vous pouvez travailler avec une voiture.
  • Cet objet de voiture a des propriétés qui sont des composants d'une voiture qui cachent davantage à la voiture globale leurs implémentations particulières, et leurs faits de données permettant aux composants de la voiture d'être interchangeables.

La chose à noter ici est que lorsque vous modélisez des choses dans un format OO, il s'agit de représenter des choses en tant que données. Vous avez des objets avec des propriétés, beaucoup de ces propriétés sont des objets avec plus de propriétés. Vous avez ici et là quelques méthodes attachées à ces objets, mais tout ce qu'elles font est généralement de modifier les propriétés des objets de cette façon et cela, encore une fois, c'est une modélisation très centrée sur les données; c'est-à-dire que vous modélisez vos données pour qu'elles interagissent en vous concentrant sur leur structuration pour rendre disponibles tous les points de vos données afin que les consommateurs puissent modifier les données de cette façon et cela.

FP

  • Vous disposez de nombreux calculs qui vous permettent de décrire des comportements
  • Ces expressions de comportement sont liées d'une manière qui peut se traduire par la façon dont les comportements d'une voiture sont liés les uns aux autres, comme une voiture qui accélère / décélère, il y a deux comportements qui s'opposent de la même manière.

La grande différence entre OO et FP qui me frappe constamment est comme je l'ai dit ci-dessus la façon dont vous modélisez les données. En OO, comme mentionné ci-dessus, vous modélisez les données en tant que données, en FP, vous modélisez les données en tant que calculs, expressions, algorithmes, il s'agit plus de modéliser les activités de vos données que les faits. Pensez à la modélisation de données de base en mathématiques, il s'agit toujours d'obtenir une équation qui peut générer vos données, qui modélise vos données comme l'activité qui les provoque, contrairement à OO, la modélisation propose un moyen de représenter les données que vous avez. C'est en grande partie la distinction entre FP et OO.

Rappelez-vous, pendant une longue période, LISP, l'un des langages fondamentaux de FP, a vécu avec une très petite quantité de types de données primitifs. Cela fonctionne parce que l'approche ne consiste pas tant à modéliser des représentations complexes de vos données que des calculs qui génèrent et expriment les comportements de votre système.

Lorsque je commence à écrire du code dans FP, je commence par écrire du code qui fait quelque chose, alors que lorsque je commence à écrire du code en OO, je commence par écrire des modèles qui décrivent quelque chose. Le faire des choses est caché dans FP en étant des expressions, le faire des choses est exposé dans OO en étant décrit avec des données, cacher ces données limite ladite exposition.


Pour en revenir à la question, que dit FP à propos de la dissimulation de données, l'apprécie-t-elle ou est-elle en désaccord ou non?

Je dis que cela n'a pas d'importance, dans OO, vos données sont les tripes et les éléments importants de votre programme qui devraient être cachés. Dans FP, les tripes et les connaissances de votre système sont toutes cachées dans les algorithmes et les calculs qui expriment le système. Celles-ci sont par définition plus ou moins immuables, la seule façon de muter les expressions de calcul sont des choses comme les macros, mais même dans ce cas, les définitions de mutations sont des expressions elles-mêmes qui ne peuvent pas être encore plus manipulées.

Jimmy Hoffa
la source
c'est génial, j'ai vraiment aimé le lire. Merci pour votre contribution
Chris McCall
5

Il y a un peu de paradoxe ici. Même si la programmation fonctionnelle se concentre sur les fonctions, et a souvent des fonctions qui fonctionnent directement sur les types de données primitifs, elle a tendance à cacher plus de données que la programmation orientée objet.

Comment en est-il ainsi? Pensez à une belle interface OO qui cache les données sous-jacentes - peut-être des collections (j'essaie de choisir quelque chose de presque omniprésent). Vous n'aurez peut-être pas besoin de connaître le type sous-jacent des objets de la collection ou le type d'objet implémentant la collection, tant que vous savez que la collection implémente, par exemple, IEnumerable. Vous avez donc des données qui se cachent.

Dans la programmation fonctionnelle, vous pouvez écrire une fonction qui fonctionne efficacement avec une interface IEnumerable, mais qui fonctionne sur un type de données primitif (ou sur n'importe quel type de données). Mais que faire si le type n'a jamais implémenté les méthodes IEnumerable? Voici la clé, vous pouvez toujours avoir les "méthodes" qui forment les pièces nécessaires de "l'interface" être des paramètres transmis à votre fonction. Ou vous pouvez assembler des fonctions avec des données et faire des choses comme une OO.

Notez que dans les deux cas, vous ne cachez pas moins de données que dans OO. Ma fonction générale qui fonctionne sur n'importe quel type n'accède clairement pas aux données de ce type - cela se produit dans les fonctions passées en tant que paramètres à la fonction générale, mais la fonction générale ne jette jamais un œil à l'intérieur de ces fonctions pour voir les données.

Donc, en ce qui concerne votre point 1, je ne pense pas que FP et l'article soient vraiment en désaccord. Je ne pense pas que votre caractérisation de FP ne cachant pas de données soit correcte. On pourrait certainement mettre en œuvre le design que l'auteur a préféré dans FP.

En ce qui concerne le point 4 (2 et 3 n'ont pas de sens pour répondre étant donné ce que j'ai dit pour le point 1), cela varie. Il varie également dans les langues OO et, dans de nombreux domaines privés, il est privé par convention plutôt que appliqué par la langue.

psr
la source
En d'autres termes: en programmation fonctionnelle, beaucoup plus est "caché" par défaut, simplement parce qu'il n'existe même pas! Seuls les éléments que vous mettez explicitement dans le champ d'application sont "non masqués".
leftaroundabout
3

Tout d'abord, merci pour le lien vers cet excellent article, je ne le savais pas jusqu'à présent, et cela m'a donné une grande contribution sur certaines choses dont je discutais avec d'autres concepteurs de logiciels de la communauté ces dernières années. Voici mon avis à ce sujet:

Je veux d'abord savoir si mon évaluation est correcte. Le paradigme de la PF et cet article sont-ils philosophiquement en désaccord?

La conception de FP se concentre beaucoup sur le flux de données (ce qui est à mon humble avis pas aussi mauvais que l'article peut le laisser entendre). S'il s'agit d'un "désaccord" complet, on peut faire valoir.

En supposant qu'ils ne sont pas d'accord, comment FP "compense" -il le manque de données cachées? Peut-être sacrifient-ils le masquage des données mais gagnent-ils X, Y et Z. J'aimerais connaître le raisonnement pour lequel X, Y et Z sont considérés comme plus bénéfiques que le masquage des données.

À mon humble avis, il ne compense pas. Voir ci-dessous.

Ou, en supposant qu'ils ne sont pas d'accord, FP pense peut-être que le masquage des données est mauvais. Si oui, pourquoi pense-t-il que le masquage des données est mauvais?

Je ne pense pas que la plupart des utilisateurs ou des concepteurs de FP ressentent ou pensent de cette façon, voir ci-dessous.

En supposant qu'ils soient d'accord, j'aimerais savoir ce qu'est la mise en œuvre par les FP de la dissimulation des données. Il est évident de voir cela dans OOP. Vous pouvez avoir un champ privé auquel personne en dehors de la classe ne peut accéder. Il n'y a pas d'analogie évidente avec cela dans FP.

Voici le point - vous avez probablement vu tant de systèmes OOP implémentés de manière non fonctionnelle que vous pensez que l'OOP n'est pas fonctionnel. Et c'est une erreur, IMHO OOP et FP sont principalement des concepts orthogonaux, et vous pouvez parfaitement construire des systèmes OO fonctionnels, ce qui vous donne une réponse évidente à votre question. L'implémentation classique "objet" dans FP se fait en utilisant des fermetures , et si vous voulez que les objets soient utilisés dans un système fonctionnel, le point clé est de les concevoir immuables.

Donc, pour créer des systèmes plus grands, à mon humble avis, vous pouvez créer des modules, des classes et des objets en utilisant les concepts OO, exactement de la manière décrite sous "Modularisation 2" dans l'article sans quitter le "chemin FP". Vous utiliserez le concept de module de votre langage FP préféré, rendrez tous vos objets immuables et utiliserez le "meilleur des deux mondes".

Doc Brown
la source
3

TL; DR : Non

Le paradigme de la PF et cet article sont-ils philosophiquement en désaccord?.

Non, ce n'est pas le cas. La programmation fonctionnelle est déclarative qui est «un style de construction de la structure et des éléments des programmes informatiques, qui exprime la logique d'un calcul sans décrire son flux de contrôle». Il s'agit moins de suivre l'organigramme et plus de créer des règles qui permettent au flux de se produire de lui-même.

La programmation procédurale est beaucoup plus proche d'un encodage d'un organigramme que la programmation fonctionnelle. Il s'ensuit que les transformations qui se produisent et codent ces transformations en procédures qui sont exécutées dans l'ordre, exactement comme le flux décrit dans un organigramme.

Alors que les langages procéduraux modélisent l'exécution du programme comme une séquence de commandes impératives qui peuvent implicitement modifier l'état partagé, les langages de programmation fonctionnels modélisent l'exécution comme l'évaluation d'expressions complexes qui ne dépendent que les unes des autres en termes d'arguments et de valeurs de retour. Pour cette raison, les programmes fonctionnels peuvent avoir un ordre d'exécution de code plus libre, et les langages peuvent offrir peu de contrôle sur l'ordre dans lequel les différentes parties du programme sont exécutées. (Par exemple, les arguments d'un appel de procédure dans Scheme sont exécutés dans un ordre arbitraire.)

Masquage des données

  • La programmation fonctionnelle a ses propres méthodes de masquage des données, par exemple pensez aux fermetures . Il s'agit de données masquées par encapsulation dans une fermeture. Il est difficile pour les champs d'être des données plus privées qui ont été fermées, car seule la fermeture a une référence aux données et vous ne pouvez pas y faire référence en dehors de la fermeture.
  • L'une des raisons du masquage des données est de stabiliser l'interface de programmation en masquant les données en mutation. La programmation fonctionnelle n'a pas de données en mutation, donc elle n'a pas besoin de cacher autant de données.
Dietbuddha
la source
3
"La programmation fonctionnelle n'a pas de données en mutation, donc elle n'a pas besoin de cacher autant de données." - c'est une affirmation très trompeuse. Vous avez dit vous-même (et je suis d'accord) que l' une des raisons de l'encapsulation du comportement est d'avoir un contrôle sur la mutation des données. Mais conclure que l'absence de mutation rend presque l'encapsulation inutile est un énorme tronçon. Les ADT et l'abstraction des données en général sont omniprésents dans la littérature et les systèmes de PF.
Thiago Silva
Je n'ai jamais dit que cela "rend presque l'encapsulation inutile". Ce sont vos pensées et les vôtres seules. J'ai dit que vous n'avez pas besoin de cacher autant de données en raison du manque de variables mutantes. Cela ne rend pas l'encapsulation ou la dissimulation de données inutiles, cela réduit simplement son utilisation car ces cas n'existent pas. Tous les autres cas dans lesquels le masquage et l'encapsulation de données sont utiles sont toujours valables.
dietbuddha