Après avoir appris la programmation fonctionnelle en Haskell et F #, le paradigme OOP semble à l'envers avec des classes, des interfaces, des objets. Quels aspects de la PF puis-je apporter au travail que mes collègues peuvent comprendre? Y a-t-il des styles de PF qui valent la peine de parler à mon patron de la reconversion de mon équipe afin que nous puissions les utiliser?
Aspects possibles de la PF:
- Immutabilité
- Application partielle et curry
- Fonctions de première classe (pointeurs de fonction / objets fonctionnels / modèle de stratégie)
- Évaluation paresseuse (et monades)
- Fonctions pures (pas d'effets secondaires)
- Expressions (vs déclarations - chaque ligne de code produit une valeur au lieu de, ou en plus de provoquer des effets secondaires)
- Récursivité
- Correspondance de motifs
Est-ce un libre-service où nous pouvons faire tout ce que le langage de programmation prend en charge dans la mesure où ce langage le prend en charge? Ou existe-t-il une meilleure ligne directrice?
Réponses:
La programmation fonctionnelle est un paradigme différent de la programmation orientée objet (un état d'esprit différent et une façon différente de penser les programmes). Vous avez commencé à réaliser qu'il existe plus d'une façon (orientée objet) de penser aux problèmes et à leurs solutions. Il en existe d'autres (la programmation procédurale et générique me vient à l'esprit). La façon dont vous réagissez à ces nouvelles connaissances, si vous acceptez et intégrez ces nouveaux outils et approches dans votre ensemble de compétences, déterminera si vous grandissez et devenez un développeur plus complet et compétent.
Nous sommes tous formés pour gérer et sommes à l'aise avec un certain niveau de complexité. J'aime appeler cela la limite des prairies d' une personne (de Watership Down, à quelle hauteur pouvez-vous compter). C'est une bonne chose d'élargir votre esprit, votre capacité à considérer plus d'options et à avoir plus d'outils pour aborder et résoudre les problèmes. Mais c'est un changement, et cela vous sort de votre zone de confort.
Un problème que vous pouvez rencontrer est que vous deviendrez moins content de suivre la foule "tout est un objet". Vous devrez peut-être faire preuve de patience lorsque vous travaillez avec des personnes qui ne comprennent pas (ou ne veulent pas comprendre) pourquoi une approche fonctionnelle du développement logiciel fonctionne bien pour certains problèmes. Tout comme une approche de programmation générique fonctionne bien pour certains problèmes.
Bonne chance!
la source
La programmation fonctionnelle permet une productivité très pratique et terre-à-terre dans l'écriture de code de tous les jours: certaines fonctionnalités favorisent la concision, ce qui est excellent car moins vous écrivez de code, moins vous faites d'échecs et moins de maintenance est requise.
En tant que mathématicien, je trouve les fonctionnalités fonctionnelles très attrayantes, mais elles sont généralement utiles lors de la conception d'une application: ces structures peuvent encoder dans la structure du programme beaucoup d'invariants du programme, sans représenter ces invariants par des variables.
Ma combinaison préférée peut sembler assez banale, je pense cependant qu'elle a un impact très élevé sur la productivité. Cette combinaison est une application partielle et des fonctions de curry et de première classe que je ré-étiqueterais ne jamais réécrire une boucle for : passez plutôt le corps de la boucle à une fonction d'itération ou de mappage. J'ai récemment été embauché pour un travail en C ++ et j'ai remarqué de manière amusante, j'ai totalement perdu l'habitude d'écrire des boucles pour!
La combinaison de la récursivité et de la mise en correspondance de modèles annihile la nécessité de ce modèle de conception de visiteur . Il suffit de comparer le code dont vous avez besoin pour programmer un évaluateur d'expressions booléennes: dans tout langage de programmation fonctionnel, cela devrait être d'environ 15 lignes de code, dans la POO, la bonne chose à faire est d'utiliser ce modèle de conception de visiteur , qui transforme cet exemple de jouet en un essai approfondi. Les avantages sont évidents et je n'ai connaissance d'aucun inconvénient.
la source
list.forEach(System.out::println);
D'un point de vue FP,println
est une fonction qui prend deux arguments, une ciblePrintStream
et une valeur ,Object
mais laCollection
deforEach
méthode prévoit une fonction avec un seul argument qui peut être appliqué à chaque élément. Ainsi, le premier argument est lié à l'instance trouvée enSystem.out
cédant à une nouvelle fonction avec un argument. C'est plus simple queBiConsumer<…> c=PrintStream::println; PrintStream a1=System.out; list.forEach(a2 -> c.accept(a1, a2));
Vous devrez peut-être restreindre les parties de vos connaissances que vous utilisez au travail, la façon dont Superman doit prétendre être Clark Kent afin de profiter des avantages d'une vie normale. Mais en savoir plus ne vous fera jamais de mal. Cela dit, certains aspects de la programmation fonctionnelle sont appropriés pour une boutique orientée objet, et d'autres aspects peuvent valoir la peine d'être discutés avec votre patron afin que vous puissiez augmenter le niveau moyen de connaissances de votre boutique et ainsi obtenir un meilleur code.
FP et OOP ne s'excluent pas mutuellement. Regardez Scala. Certains pensent que c'est le pire parce que c'est une PF impure, mais certains pensent que c'est le meilleur pour la même raison.
Un par un, voici quelques aspects qui fonctionnent très bien avec la POO:
Fonctions pures (pas d'effets secondaires) - Tous les langages de programmation que je connais le supportent. Ils rendent votre code beaucoup, beaucoup plus facile à raisonner et doivent être utilisés chaque fois que cela est possible. Vous n'avez pas à l'appeler FP. Il suffit d'appeler cela de bonnes pratiques de codage.
Immuabilité: la chaîne est sans doute l'objet Java le plus utilisé et il est immuable. Je couvre les objets Java immuables et les collections Java immuables sur mon blog. Certaines de ces informations peuvent vous être applicables.
Fonctions de première classe (pointeurs de fonction / objets fonctionnels / modèle de stratégie) - Java en a une version mutante entravée depuis la version 1.1 avec la plupart des classes d'API (et il y en a des centaines) qui implémentent l'interface d'écoute. Runnable est probablement l'objet fonctionnel le plus utilisé. Les fonctions de première classe représentent plus de travail pour coder dans un langage qui ne les prend pas en charge nativement, mais elles valent parfois l'effort supplémentaire lorsqu'elles simplifient d'autres aspects de votre code.
La récursivité est utile pour traiter les arbres. Dans un magasin OOP, c'est probablement la principale utilisation appropriée de la récursivité. L'utilisation de la récursivité pour le plaisir dans OOP devrait probablement être désapprouvée si, pour aucune autre raison que la plupart des langages OOP n'ont pas l'espace de pile par défaut pour en faire une bonne idée.
Expressions (par rapport aux instructions - chaque ligne de code produit une valeur au lieu de, ou en plus de provoquer des effets secondaires) - Le seul opérateur évaluatif en C, C ++ et Java est l' opérateur ternaire . Je discute de l'utilisation appropriée sur mon blog. Vous pouvez trouver que vous écrivez quelques fonctions simples qui sont hautement réutilisables et évaluatives.
Évaluation paresseuse (et monades) - principalement limitée à l'initialisation paresseuse dans la POO. Sans fonctionnalités linguistiques pour le prendre en charge, vous pouvez trouver certaines API utiles, mais il est difficile d'écrire les vôtres. Optimisez votre utilisation des flux à la place - voir les interfaces Writer et Reader pour des exemples.
Application partielle et curry - Pas pratique sans fonctions de première classe.
Correspondance de motif - généralement déconseillé dans la POO.
En résumé, je ne pense pas que le travail devrait être un libre-service où vous pouvez faire tout ce que le langage de programmation prend en charge à la limite de ce langage. Je pense que la lisibilité par vos collègues devrait être votre test décisif pour le code conçu pour la location. Là où cela vous irrite le plus, je voudrais envisager de commencer des études au travail pour élargir les horizons de vos collègues.
la source
public interface BiConsumer<T, U> { public void accept(T t, U u); }
il existe d'autres interfaces fonctionnelles utiles dans java.util.function.Most OOP languages don't have the stack space for it
Vraiment? Tout ce dont vous avez besoin est de 30 niveaux de récursivité pour gérer des milliards de nœuds dans un arbre binaire équilibré. Je suis presque sûr que mon espace de pile convient à beaucoup plus de niveaux que cela.En plus de la programmation fonctionnelle et de la programmation orientée objet, il existe également une programmation déclarative (SQL, XQuery). L'apprentissage de chaque style vous aide à acquérir de nouvelles connaissances et vous apprendrez à choisir le bon outil pour le travail.
Mais oui, il peut être très frustrant d'écrire du code dans un langage et de savoir que si vous utilisiez autre chose, vous pourriez être bien plus productif pour un domaine à problème particulier. Cependant, même si vous utilisez un langage comme Java, il est possible d'appliquer des concepts de FP à votre code Java, quoique de manière détournée. Le framework Guava, par exemple, fait une partie de cela.
la source
En tant que programmeur, je pense que vous ne devriez jamais arrêter d'apprendre. Cela dit, il est très intéressant d'apprendre que la PF altère vos compétences en POO. J'ai tendance à penser qu'apprendre la POO comme apprendre à faire du vélo; tu n'oublies jamais comment le faire.
En apprenant les tenants et les aboutissants de la FP, je me suis retrouvé à penser plus mathématiquement et à avoir une meilleure perspective des moyens par lesquels j'écris des logiciels. Voilà mon expérience personnelle.
À mesure que vous gagnez en expérience, les concepts de programmation de base seront beaucoup plus difficiles à perdre. Je vous suggère donc de vous détendre sur le FP jusqu'à ce que les concepts de POO soient totalement solidifiés dans votre esprit. La PF est un changement de paradigme certain. Bonne chance!
la source
Il existe déjà de nombreuses bonnes réponses, donc la mienne répondra à un sous-ensemble de votre question; à savoir, je prends ombrage à la prémisse de votre question, car la POO et les fonctionnalités ne s'excluent pas mutuellement.
Si vous utilisez C ++ 11, il y a beaucoup de ces types de fonctionnalités de programmation fonctionnelle intégrées dans la bibliothèque langage / standard qui se synergisent (assez) bien avec la POO. Bien sûr, je ne sais pas dans quelle mesure TMP sera bien reçu par votre patron ou vos collègues, mais le fait est que vous pouvez obtenir bon nombre de ces fonctionnalités sous une forme ou une autre dans des langages non fonctionnels / OOP, comme C ++.
L'utilisation de modèles avec la récursion de temps de compilation repose sur vos 3 premiers points,
Dans la mesure où les valeurs de modèle sont immuables (constantes au moment de la compilation), toute itération est effectuée à l'aide de la récursivité, et la ramification est effectuée à l'aide (plus ou moins) de correspondance de modèle, sous la forme d'une résolution de surcharge.
Comme pour les autres points, l'utilisation de
std::bind
etstd::function
vous donne une application de fonction partielle et des pointeurs de fonction sont intégrés au langage. Les objets appelables sont des objets fonctionnels (ainsi qu'une application de fonction partielle). Notez que par objets appelables, je veux dire ceux qui définissent leuroperator ()
.L'évaluation paresseuse et les fonctions pures seraient un peu plus difficiles; pour les fonctions pures, vous pouvez utiliser des fonctions lambda qui ne capturent que par valeur, mais ce n'est pas idéal.
Enfin, voici un exemple d'utilisation de la récursion au moment de la compilation avec une application de fonction partielle. C'est un exemple quelque peu artificiel, mais il démontre la plupart des points ci-dessus. Il liera récursivement les valeurs d'un tuple donné à une fonction donnée et générera un objet fonction (appelable)
la source