Je suis intéressé par un meilleur apprentissage de la programmation fonctionnelle. Pour ce faire, il me semble évident que je devrais me forcer à utiliser le langage de programmation fonctionnel le plus pur possible. Par conséquent, je demande ici, plus ou moins, un ordre des langages de programmation fonctionnels en fonction de leur pureté.
Il me semble qu'il serait plus pratique d'apprendre Lisp ou Clojure (ou Scheme, ou Scala, etc.), mais pour ce que j'ai entendu récemment, Haskell serait très difficile à battre pour enseigner les principes de programmation fonctionnelle à quelqu'un. Je n'en suis pas encore sûr, alors je vous demande: quel est le langage de programmation fonctionnel le plus pur? Une commande serait formidable si plusieurs se disputent le magnifique titre du langage de programmation fonctionnel le plus pur.
Réponses:
Il n'y a pas d'échelle pour évaluer le degré de pureté des langages fonctionnels. Si le langage permet des effets secondaires, c'est impur, sinon c'est pur. Selon cette définition, Haskell, Mercury, Clean, etc. sont de purs langages fonctionnels; tandis que Scala, Clojure, F #, OCaml etc. sont impurs.
EDIT: Peut-être que j'aurais dû formuler ceci comme "si le langage ne permet pas d'effets secondaires sans en informer le système de type , c'est pur. Sinon c'est impur.".
la source
IO
monade). C'est juste que le code provoquant des effets secondaires est clairement marqué comme tel. Je ne pense pas du tout qu'il soit utile de parler de langages purs / impurs (Haskell vous permet de programmer impérativement! Gasp!) /impur.IO
monade est pure. C'est la bibliothèque d'exécution qui ne l'est pas, pas votre code, car votremain
fonction est essentiellement un énorme transformateur d'état. (Quelque chose commemain :: World -> World
dans les coulisses)program = "some C code"
, puis l'environnement d'exécution traite du code C. :-)Puisque l'apprentissage est votre objectif, et non l'écriture de programmes en soi, vous ne pouvez pas obtenir plus pur que Lambda Calculus .
Lambda Calculus existait avant l'invention des ordinateurs. Il a fallu plusieurs logiciens qualifiés pour travailler sur la façon de faire la soustraction (pendant un certain temps, il a été théorisé que seules l'addition et la multiplication étaient possibles).
Apprendre comment les booléens et les nombres
if
peuvent être inventés à partir de rien ne mettra plus de gaz dans votre réservoir, mais cela rendra votre réservoir beaucoup plus grand.la source
-1
.Les langages impurs ne diffèrent pas vraiment en principe des langages impératifs plus familiers, surtout maintenant que de nombreuses astuces fonctionnelles ont été copiées. Ce qui est différent, c'est le style - comment résoudre les problèmes.
Que vous comptiez Haskell comme pur, ou que vous comptiez la monade IO comme impureté, le style Haskell est une forme extrême de ce style et mérite d'être étudié.
La monade Haskell IO est dérivée de la théorie mathématique des monades (bien sûr). Cependant, pour les programmeurs impératifs, je pense qu'une manière à l'envers d'arriver aux monades a plus de sens.
Phase un - un langage fonctionnel pur peut facilement renvoyer une grande valeur de chaîne comme résultat. Cette grosse chaîne peut être le code source d'un programme impératif, dérivé de manière purement fonctionnelle de certains paramètres spécifiant les exigences. Vous pouvez ensuite créer un compilateur de "niveau supérieur" qui exécute votre générateur de code, puis alimente automatiquement ce code généré dans le compilateur de langage impératif.
Phase deux - plutôt que de générer du code source textuel, vous générez un arbre de syntaxe abstraite fortement typé. Votre compilateur en langage impératif est absorbé dans votre compilateur de "niveau supérieur" et accepte l'AST directement comme code source. C'est beaucoup plus proche de ce que fait Haskell.
C'est toujours gênant, cependant. Par exemple, vous avez deux types de fonctions distinctes - celles évaluées pendant la phase de génération de code et celles exécutées lors de l'exécution du programme généré. C'est un peu comme la distinction entre les fonctions et les modèles en C ++.
Donc, pour la phase 3, rendez les deux identiques - la même fonction avec la même syntaxe peut être partiellement évaluée pendant la «génération de code», ou entièrement évaluée, ou pas du tout évaluée. En outre, jetez tous les nœuds AST de construction en boucle en faveur de la récursivité. En fait, rejetez l'idée des nœuds AST en tant que type spécial de données - ne disposez pas de nœuds AST à "valeur littérale", mais simplement de valeurs, etc.
C'est à peu près ce que fait la monade IO - l'opérateur de liaison est un moyen de composer des "actions" pour former des programmes. Ce n'est rien de spécial - juste une fonction. De nombreuses expressions et fonctions peuvent être évaluées lors de la "génération de code", mais celles qui dépendent des effets secondaires d'E / S doivent avoir une évaluation retardée jusqu'à l'exécution - non pas par une règle spéciale, mais comme une conséquence naturelle des dépendances des données dans expressions.
Les monades en général ne sont que de la généralisation - elles ont la même interface, mais implémentent les opérations abstraites différemment, donc au lieu d'évaluer une description de code impératif, elles évaluent plutôt autre chose. Avoir la même interface signifie qu'il y a certaines choses que vous pouvez faire aux monades sans vous soucier de quelle monade, ce qui s'avère utile.
Cette description fera sans aucun doute exploser les têtes des puristes, mais elle explique pour moi certaines des vraies raisons pour lesquelles Haskell est intéressant. Il brouille la frontière entre programmation et métaprogrammation, et utilise les outils de programmation fonctionnelle pour réinventer la programmation impérative sans avoir besoin d'une syntaxe particulière.
Une critique que j'ai des modèles C ++ est qu'ils sont une sorte de sous-langage fonctionnel pur cassé dans un langage impératif - pour évaluer la même fonction de base au moment de la compilation plutôt qu'au moment de l'exécution, vous devez la réimplémenter en utilisant un style complètement différent de codage. Dans Haskell, bien que l'impureté doive être étiquetée comme telle dans son type, la même fonction exacte peut être évaluée à la fois dans un sens de méta-programmation et dans un sens d'exécution hors méta-programmation dans le même programme - il n'y a pas de ligne dure entre programmation et métaprogrammation.
Cela dit, il existe des métaprogrammations que Haskell standard ne peut pas faire, essentiellement parce que les types (et peut-être quelques autres choses) ne sont pas des valeurs de première classe. Il existe cependant des variantes linguistiques qui tentent de résoudre ce problème.
Beaucoup de choses que j'ai dites sur Haskell peuvent être appliquées dans des langages fonctionnels impurs - et parfois même des langages impératifs. Haskell est différent parce que vous n'avez pas d'autre choix que d'adopter cette approche - cela vous oblige essentiellement à apprendre ce style de travail. Vous pouvez «écrire C en ML», mais vous ne pouvez pas «écrire C en Haskell» - du moins pas sans savoir ce qui se passe sous le capot.
la source
Personnellement, je classe les langues en trois niveaux de pureté fonctionnelle:
Langages fonctionnels purs - c'est-à-dire ceux qui traitent l'intégralité de votre programme comme une fonction pure et gèrent la mutabilité uniquement par l'interaction avec le runtime - Haskell est probablement l'exemple canonique
Langages fonctionnels impurs - c'est-à-dire ceux qui mettent l'accent sur un style fonctionnel mais qui permettent des effets secondaires. Clojure est clairement dans cette catégorie (il permet la mutation de façon contrôlée dans le cadre de son framework STM), également OCaml ou F #
Langages multi-paradigmes - ce ne sont pas des langages fonctionnels avant tout, mais peuvent prendre en charge un style fonctionnel en utilisant des fonctions de première classe, etc. Scala est un bon exemple ici, je mettrais également Common Lisp dans cette catégorie et vous pourriez même inclure des langages comme JavaScript .
Dans votre situation, je suggère d'abord d'apprendre Haskell, puis Clojure. C'est ce que j'ai fait et cela a très bien fonctionné pour moi! Haskell est magnifique et vous enseigne les principes fonctionnels les plus purs, Clojure est beaucoup plus pragmatique et vous aide à faire beaucoup de choses tout en étant très fonctionnel dans l'âme.
Je ne considère pas vraiment la troisième catégorie comme des langages fonctionnels (bien qu'après avoir appris Haskell et Clojure, je me retrouve souvent à profiter des techniques fonctionnelles lors de leur utilisation!)
la source
Si un langage fonctionnel pur est tel, qui n'a que des fonctions pures (routines qui n'ont pas d'effets secondaires), alors c'est un peu inutile, car il ne peut pas lire d'entrée ou écrire de sortie;)
Parce que c'est vraiment pour apprendre, je pense que l'isolement n'est pas nécessairement la voie à suivre. La programmation fonctionnelle est un paradigme. Il est important de comprendre quels paradigmes conviennent à quels problèmes et, surtout, comment les combiner au mieux.
En dehors de cela, si vous recherchez la "pureté", vous voudrez peut-être jeter un œil à Pure . Notez cependant que l'extrême facilité d'appeler des routines C le rend fonctionnellement impur (mais aussi très puissant).
la source
Pas une réponse entièrement sérieuse, mais Unlambda doit être un concurrent. Vous ne pouvez pas obtenir plus de fonctionnalités «pures» que les combinateurs SKI.
la source
Erlang, Haskell, Scheme, Scala, Clojure et F #
Cette question vous aiderait probablement mieux dans votre recherche également .
la source
set!
(entre autres) ...