Au cours des dernières années, les fonctions anonymes (fonctions AKA lambda) sont devenues une construction de langage très populaire et presque tous les langages de programmation majeurs / grand public les ont introduites ou sont prévues pour les introduire dans une prochaine révision de la norme.
Pourtant, les fonctions anonymes sont un concept très ancien et très connu en mathématiques et en informatique (inventé par le mathématicien Alonzo Church vers 1936 et utilisé par le langage de programmation Lisp depuis 1958, voir par exemple ici ).
Alors, pourquoi les langages de programmation traditionnels (dont beaucoup sont nés il y a 15 ou 20 ans) ne prennent-ils pas en charge les fonctions lambda depuis le début et ne les ont-ils introduits que plus tard?
Et qu'est-ce qui a déclenché l'adoption massive de fonctions anonymes ces dernières années? Existe-t-il un événement spécifique, une nouvelle exigence ou une technique de programmation à l'origine de ce phénomène?
NOTE IMPORTANTE
L'objet de cette question est l'introduction de fonctions anonymes dans les langages modernes (et donc, peut-être à quelques exceptions près, non fonctionnels). Notez également que des fonctions anonymes (blocs) sont présentes dans Smalltalk, qui n'est pas un langage fonctionnel, et que des fonctions nommées normales sont présentes même dans des langages procéduraux tels que C et Pascal.
Veuillez ne pas trop généraliser vos réponses en parlant de "l’adoption du paradigme fonctionnel et de ses avantages", car ce n’est pas le sujet de la question.
la source
Réponses:
Il y a certainement une tendance notable vers la programmation fonctionnelle, ou du moins certains de ses aspects. Certains des langages populaires ayant à un moment adopté des fonctions anonymes sont le C ++ ( C ++ 11 ), PHP ( PHP 5.3.0 ), C # ( C # v2.0 ), Delphi (depuis 2009), Objective C ( blocs ), tandis que Java 8 apportera un soutien pour les lambdas à la langue . Et il existe des langages populaires qui ne sont généralement pas considérés comme fonctionnels, mais pris en charge depuis le début, ou du moins au début, par des fonctions anonymes, le meilleur exemple étant JavaScript.
Comme pour toutes les tendances, essayer de rechercher un événement unique qui les a déclenchées est probablement une perte de temps, il s'agit généralement d'une combinaison de facteurs, dont la plupart ne sont pas quantifiables. Pratique Common Lisp , publié en 2005, peut avoir joué un rôle important dans la nouvelle attention à Lisp en tant que pratique la langue, comme pour un certain Lisp temps était la plupart du temps une langue que vous souhaitez rencontrer dans un cadre universitaire ou des marchés de niche très spécifiques. La popularité de JavaScript a peut-être également joué un rôle important dans l’attention portée aux fonctions anonymes, comme l'explique munificent dans sa réponse .
Outre l'adoption de concepts fonctionnels issus de langages multi-usages, il existe également un changement notable vers les langages fonctionnels (ou principalement fonctionnels). Des langues comme Erlang (1986), Haskell (1990), OCaml (1996), Scala (2003), F # (2005), Clojure (2007) et même des langues spécifiques à un domaine comme R (1993) semblent avoir acquis une forte popularité. après leur introduction. La tendance générale a attiré l'attention sur les langages fonctionnels plus anciens, comme Scheme (1975) et, bien entendu, le Common Lisp.
Je pense que l’événement le plus important est l’adoption de la programmation fonctionnelle dans l’industrie. Je ne sais absolument pas pourquoi cela n’était pas le cas auparavant, mais il me semble qu’à un moment donné, au début et au milieu des années 90, la programmation fonctionnelle a commencé à trouver sa place dans l’industrie, à commencer (peut-être) par la prolifération d’ Erlang dans télécommunications et l'adoption de Haskell dans l'aérospatiale et la conception de matériel .
Joel Spolsky a écrit un article de blog très intéressant, The Perils of JavaSchools , dans lequel il s'oppose à la tendance des universités à privilégier Java par rapport à d'autres langues, peut-être plus difficiles à apprendre. Bien que le blog ait peu à voir avec la programmation fonctionnelle, il identifie un problème clé:
Je me souviens encore combien je détestais Lisp lorsque je l'ai rencontrée pour la première fois à l'université. C'est définitivement une maîtresse dure, et ce n'est pas une langue dans laquelle vous pouvez être immédiatement productif (enfin, au moins, je ne pouvais pas). Comparé à Lisp, Haskell (par exemple) est beaucoup plus convivial, vous pouvez être productif sans trop d'effort et sans vous sentir complètement idiot, ce qui pourrait également constituer un facteur important dans le passage à la programmation fonctionnelle.
Dans l'ensemble, c'est une bonne chose. Plusieurs langages à usages multiples adoptent des concepts de paradigme qui semblaient parfois obscurs à la plupart de leurs utilisateurs, et l'écart entre les paradigmes principaux se réduit.
Questions connexes:
Lectures complémentaires:
la source
Je trouve intéressant de constater combien la popularité de la programmation fonctionnelle a été parallèle à la croissance et à la prolifération de Javascript. Le langage Javascript présente de nombreuses fonctionnalités radicales dans le spectre de la programmation fonctionnelle qui, au moment de sa création (1995), n’étaient pas très populaires parmi les langages de programmation traditionnels (C ++ / Java). Il est soudainement devenu le seul langage de programmation Web côté client. Tout à coup, beaucoup de programmeurs devaient simplement connaître le langage Javascript et par conséquent, connaître les fonctionnalités du langage de programmation fonctionnel.
Je me demande quelle serait la popularité des langages / fonctionnalités fonctionnels sans l’augmentation soudaine de Javascript.
la source
Les gestionnaires d’événements JavaScript et DOM signifiaient que des millions de programmeurs devaient au moins apprendre un peu plus sur les fonctions de première classe afin de réaliser toute interactivité sur le Web.
À partir de là, les fonctions anonymes sont relativement courtes . Comme JavaScript ne ferme pas
this
, il vous encourage également vivement à en apprendre davantage sur les fermetures. Et puis vous êtes en or: vous comprenez des fonctions anonymes de première classe qui se superposent à des portées lexicales.Une fois que vous êtes à l'aise avec cela, vous le voulez dans toutes les langues que vous utilisez.
la source
Ce n'est certainement pas le seul facteur, mais je soulignerai la popularité de Ruby. Ne pas dire que cela est plus important que l'une des six réponses déjà inscrites au tableau, mais je pense que beaucoup de choses se sont produites en même temps et qu'il est utile de toutes les énumérer.
Ruby n’est pas un langage fonctionnel et ses lambdas, ses émules et ses blocs semblent maladroits quand vous avez utilisé quelque chose comme ML, mais le fait est qu’il a popularisé la notion de mapping et de réduction à une génération de jeunes programmeurs fuyant Java et PHP pour hipper les pâturages. Les lambda en plusieurs langues semblent être des mouvements défensifs plus que toute autre chose ("Restez dans le coin! Nous les avons aussi !!"
Mais la syntaxe de bloc et la façon dont elle s’intégrait avec .each, .map, .reduce et ainsi de suite ont popularisé l’idée d’une fonction anonyme même si c’est vraiment une construction syntaxique qui se comporte comme une coroutine. Et la conversion facile en proc via et en fait un médicament passerelle pour la programmation fonctionnelle.
Je soutiens que les programmeurs de Ruby on Rails écrivant en JavaScript étaient déjà prêts à faire des choses dans un style fonctionnel léger. Ajoutez à cela les blogs de programmeurs, l'invention de Reddit, le hacker News et le débordement de pile à peu près au même moment, et les idées se propagent plus rapidement sur Internet qu'à l'époque de Newsgroups.
TL; DR: Ruby, Rails, JavaScript, les blogs et Reddit / Hacker News / Stack Overflow ont propulsé les idées fonctionnelles vers un marché de masse, de sorte que tout le monde les souhaitait dans les langues existantes pour éviter de nouvelles défections.
la source
Comme Yannis l'a souligné, plusieurs facteurs ont influencé l'adoption de fonctions de haut niveau dans des langues qui étaient auparavant dépourvues. L’un des points importants qu’il a abordé à la légère est la prolifération de processeurs multicœurs et, partant, le souhait d’un traitement plus parallèle et simultané.
Le style de programmation fonctionnelle carte / filtre / réduction est très favorable à la parallélisation, permettant au programmeur d'utiliser facilement plusieurs cœurs, sans écrire de code de thread explicite.
Comme le note Giorgio, la programmation fonctionnelle ne se limite pas à des fonctions d'ordre élevé. Les fonctions, plus un schéma de programmation carte / filtre / réduction et l’ immuabilité sont au cœur de la programmation fonctionnelle. Ensemble, ces éléments constituent de puissants outils de programmation parallèle et simultanée. Heureusement, de nombreux langages supportent déjà une certaine notion d'immutabilité et, même s'ils ne le font pas, les programmeurs peuvent traiter les choses comme immuables, permettant ainsi aux bibliothèques et au compilateur de créer et de gérer des opérations asynchrones ou parallèles.
L'ajout de fonctions d'ordre élevé à un langage est une étape importante dans la simplification de la programmation simultanée.
Mise à jour
Je vais ajouter quelques exemples plus détaillés afin de répondre aux préoccupations de Loki.
Considérez le code C # suivant qui traverse une collection de widgets, créant une nouvelle liste de prix de widgets.
Pour une grande collection de widgets ou une méthode de calcul à calculer complexe (Widget), cette boucle ne ferait pas bon usage des cœurs disponibles. Pour effectuer les calculs de prix sur différents cœurs, le programmeur devrait explicitement créer et gérer des threads, passer le travail et collecter les résultats.
Envisagez une solution une fois que des fonctions d'ordre élevé ont été ajoutées à C #:
La boucle foreach a été déplacée dans la méthode Select, masquant ses détails d'implémentation. Le programmeur n'a plus qu'à indiquer à la fonction à appliquer à chaque élément. Cela permettrait à l’implémentation Select d’exécuter les calculs dans Parallel, en gérant toutes les préoccupations de synchronisation et de gestion des threads sans l’implication du programmeur.
Mais, bien sûr, Select ne fait pas son travail en parallèle. C'est là que l'immuabilité entre en jeu. L'implémentation de Select ne sait pas que la fonction fournie (CalculateWidgets ci-dessus) n'a pas d'effets secondaires. La fonction peut changer l'état du programme en dehors de la vue de Select et de sa synchronisation, en cassant tout. Par exemple, dans ce cas, la valeur de salesTax peut être modifiée par erreur. Les langages fonctionnels purs fournissent l’immuabilité, ainsi la fonction Select (map) peut savoir avec certitude qu’aucun état ne change.
C # résout ce problème en proposant PLINQ comme alternative à Linq. Cela ressemblerait à:
Ce qui exploite pleinement tous les cœurs de votre système sans une gestion explicite de ces cœurs.
la source
cause
et unperceived affect
sans expliquer lecorrelation
. La dernière ligne IMO est le sujet de la question; mais vous n'y avez pas répondu. Pourquoi simplifie-t-il la programmation simultanée?Je suis d’accord avec beaucoup des réponses ici, mais ce qui est intéressant, c’est que lorsque j’ai appris à connaître les lambdas et que je leur sautais dessus, ce n’était pour aucune des raisons évoquées par d’autres.
Dans de nombreux cas, les fonctions lambda améliorent simplement la lisibilité de votre code. Avant lambdas lorsque vous appelez une méthode qui accepte un pointeur de fonction (ou une fonction, ou un délégué), vous devez définir le corps de cette fonction ailleurs. Par conséquent, lorsque vous avez la construction "foreach", votre lecteur doit passer à une autre une partie du code pour voir exactement ce que vous aviez l'intention de faire avec chaque élément.
Si le corps de la fonction qui traite les éléments ne contient que quelques lignes, j'utiliserais une fonction anonyme, car lorsque vous lisez du code, la fonctionnalité reste inchangée, mais le lecteur n'a pas à basculer, la mise en œuvre complète est juste là devant lui.
Beaucoup de techniques de programmation fonctionnelle et de parallélisation pourraient être réalisées sans fonctions anonymes; il suffit de déclarer un poste régulier et de passer une référence à cela chaque fois que vous en avez besoin. Mais avec lambdas, la facilité d’écriture du code et la facilité de lecture du code sont grandement améliorées.
la source
Ayant été un peu impliqué dans l’histoire récente, j’estime que l’un des facteurs était l’ajout de médicaments génériques à Java et .NET. Cela conduit naturellement à Func < , > et à d'autres abstractions de calcul fortement typées (Task < >, Async < > etc.)
Dans le monde .NET, nous avons ajouté ces fonctionnalités précisément pour prendre en charge la FP. Cela a déclenché un ensemble de travaux de langage en cascade liés à la programmation fonctionnelle, notamment C # 3.0, LINQ, Rx et F #. Cette progression a également influencé d’autres écosystèmes et se poursuit encore aujourd’hui en C #, F # et TypeScript.
Bien sûr, il est utile que Haskell travaille chez MSR :)
Bien sûr, il y avait beaucoup d'autres influences aussi (JS bien sûr) et ces étapes ont été à leur tour influencées par bien d'autres choses - mais l'ajout de génériques à ces langues a permis de casser l'orthodoxie rigide de la fin des années 90 dans de nombreuses parties du monde du logiciel et d'ouvrir la voie. la porte pour FP.
Don Syme
ps F # était 2003 et non 2005 - bien que nous dirions qu'il n'a pas atteint 1.0 avant 2005. Nous avons également réalisé un prototype de Haskell.NET en 2001-02.
la source
Ce n’est pas censé être une réponse sérieuse, mais la question m’a rappelé un article humoristique de James Iry - Une histoire brève, incomplète et presque incorrecte des langages de programmation qui comprend la phrase suivante:
"Les Lambda sont relégués dans une relative obscurité jusqu'à ce que Java les rend populaires en ne les ayant pas."
la source
D'après ce que je vois, la plupart des réponses se concentrent sur l'explication de la raison pour laquelle la programmation fonctionnelle en général a fait son retour et a été introduite dans le grand public. J’ai eu l’impression que cela ne répondait pas vraiment à la question des fonctions anonymes en particulier et de la raison pour laquelle elles sont devenues si populaires.
Ce qui a vraiment gagné en popularité, ce sont les fermetures . Étant donné que dans la plupart des cas, les fermetures sont des fonctions jetables transmises de manière variable, il est évidemment logique d’utiliser une syntaxe de fonction anonyme pour celles-ci. Et en fait, dans certaines langues, c'est le seul moyen de créer une clôture.
Pourquoi les fermetures ont-elles gagné en popularité? Parce qu'ils sont utiles dans la programmation événementielle lors de la création de fonctions de rappel . C'est actuellement la façon d'écrire le code client JavaScript (en fait, c'est la façon d'écrire n'importe quel code d'interface graphique). C'est actuellement aussi la manière d'écrire du code back-end hautement efficace ainsi que du code système, car le code écrit dans un paradigme basé sur les événements est généralement asynchrone et non bloquant . Pour le back-end, cela devint populaire comme solution au problème C10K .
la source
Je pense que la raison en est la prévalence croissante de la programmation concurrente et distribuée, où le cœur de la programmation orientée objet (encapsuler des états changeants avec des objets) ne s'applique plus. Dans le cas d'un système distribué, car il n'y a pas d'état partagé (et les abstractions logicielles de ce concept ont des fuites) et dans le cas d'un système simultané, une synchronisation correcte de l'accès à un état partagé s'est avérée fastidieuse et source d'erreurs. En d’autres termes, l’un des principaux avantages de la programmation orientée objet ne s’applique plus pour de nombreux programmes, ce qui rend le paradigme orienté objet beaucoup moins utile qu’il le fut auparavant.
En revanche, le paradigme fonctionnel n'utilise pas l'état mutable. Toute expérience acquise avec les paradigmes et modèles fonctionnels est donc immédiatement transférable au calcul simultané et distribué. Et au lieu de réinventer la roue, l’industrie emprunte maintenant ces schémas et fonctionnalités linguistiques pour répondre à ses besoins.
la source
Si je peux ajouter mes 0,02 €, bien que je sois d’accord avec l’importance de l’introduction du concept par JavaScript, je pense que plus que la programmation simultanée, je voudrais reprocher à la mode actuelle de la programmation asynchrone. Lorsque vous effectuez des appels asynchrones (nécessaires avec les pages Web), de simples fonctions anonymes sont tellement utiles que chaque programmeur Web (c'est-à-dire tout programmeur) devait se familiariser avec le concept.
la source
Un autre très vieux exemple de fonctions / lambdas anonymes est l' appel par nom dans Algol 60. Notez cependant que l'appel par nom est plus proche du passage de macros en tant que paramètres que du passage de vraies fonctions, et qu'il est plus fragile / difficile à comprendre en conséquence.
la source
Voici l'ascendance au mieux de ma connaissance.
la source
Les fonctions anonymes sont bien parce que nommer des choses est difficile, et si vous utilisez seulement une fonction à un endroit, elle n’a pas besoin d’un nom.
Les fonctions Lambda ont récemment été intégrées au grand public car, jusqu'à récemment, la plupart des langues ne prenaient pas en charge les fermetures.
Je dirais que Javascript a poussé ce courant dominant. C'est un langage universel qui ne permet pas d'exprimer le parallélisme et les fonctions anonymes facilitent l'utilisation des modèles de rappel. De plus, des langues populaires comme Ruby et Haskell ont contribué.
la source