Apprendre Haskell

Haskell est un langage de programmation fonctionnelle. Un style de programmation où l’on utilise des fonctions plutôt que des objets, contrairement au paradigme de la programmation orientée objet.

Je ne vais pas refaire ici la liste des caractéristiques de la programmation fonctionnelle et de Haskell en particulier. Le souhaite juste indiquer rapidement quels sont les enjeux et quelles sont les ressources que l’on peut utiliser pour s’y initier.

Pourquoi Haskell ? Parmi les nombreux langages de programmation fonctionnelle de grande valeur (Scheme, OCaml,F#, Erlang, etc), Haskell a un statut particulier car c’est le plus « pur » (il y a aussi Clean, mais plus confidentiel), c’est à dire celui qui vous contraindra le plus à embrasser le paradigme de la programmation fonctionnelle.

Les vertus de la programmation fonctionnelle sont, notamment, de pouvoir appréhender dans de bonnes conditions les problématiques de parallélisation et de concurrence induites par la crise des multicoeurs et les architectures hautement distribuées, ce pour quoi les paradigmes impératifs et objets sont dans une impasse.

L’évaluation paresseuse (lazy evaluation) permet d’optimiser les performances du code car les calculs ne sont faits par le programme que s’ils sont vraiment nécessaires.

Ensuite, le système de typage des données est statique, c’est à dire qu’il faut bien préciser la nature des données manipulées par les fonction quand on les défini. Cela peut paraître plus contraignant que le typage dynamique, mais cela garanti la sureté des programmes.

On peut dire aujourd’hui que tous les langages objets et impératifs tendent, dans leur évolution, à intégrer ce qui fait la force de la programmation fonctionnelle, alors pourquoi ne pas partir directement du modèle de référence plutôt que d’avoir des langages hybrides (scala, clojure, etc.) ?

Pour résumer la situation en matière d’évolution des langages, Simon Peyton-Jones présente le petit schéma que je reproduis ci-après, et dans lequel il montre bien que le Nirvana du programmeur serait d’avoir un langage utile et sain. Pour l’atteindre, soit l’on part du situation dangereuse mais utile (Java, C++, Python, C#, etc.) pour introduire progressivement des approches fonctionnelles dans ces langages, soit l’on part d’une situation saine (Haskell) mais peu utile (« peu utile » car dans l’idéal, un programme fonctionnel n’a aucun effet de bord, c’est à dire qu’il ne modifie pas le monde, il ne sert donc à rien) mais qui va implémenter des possibilités de modification de son environnement.

(on peut trouver sur le web plusieurs enregistrements vidéos de conférences données par Simon Peyton-Jones, toutes relèvent du gai savoir çà vaut le détour.)

On voit que la philosophie Haskell est très cartésienne : on fait une tabula rasa pour partir d’une situation saine à partir de laquelle on va accepter d’implémenter des effets de bords maîtrisés (les fameuses monades) et non arbitraires.

Là où le programmeur Java va passer son temps à gérer les effets de bords dus à son style de programmation (il ne cesse de dire au programme ce qu’il doit faire de manière procédurale puis doit ensuite faire des batteries de tests unitaires pour revérifier son travail) le développeur Haskell va laisser le programme faire son boulot. Par nature, le programmeur Haskell à confiance dans son code alors que le développeur Java est dans une relation de méfiance.

*

En matière de ressources bibliographiques, on commencera par indiquer le livre Introduction to functionnal programming using Haskell de Richard Bird. C’est un livre théorique, donc si vous êtes un développeur sans appétence pour les aspects les plus abstraits et conceptuels, il faut passer votre chemin. Toutefois, il y a fort à parier que c’est un livre que l’on sera amené à consulter régulièrement quand on se retrouvera face à des questions de fond quant à la meilleur manière de faire,  et également pour améliorer son « esprit Haskell ».

Ensuite, une mention spéciale pour l’ouvrage de Graham Hutton, Programming in Haskell, qui est un livre magique. Tout y est : qualité du papier, typographie, excellence pédagogique, le tout en moins de 200 pages. De quoi donner des leçons à tous ces livres informatiques qui ressemblent à des catalogues de la redoute de plus de 500 pages pour ne rien dire d’intelligent. Pour moi, c’est le meilleur ouvrage de programmation qu’il m’ait été donné de lire, à recommander même à ceux qui ne veulent pas apprendre Haskell, c’est dire.

C’est sur la base de ce livre qu’Erik Meijer (une des têtes pensantes de Microsoft, passionné par les langages fonctionnels) propose, sur le Channel 9 de Microsoft, 13 cours vidéos pour s’initier au langage, un vrai régal :

  1. Introduction
  2. First steps
  3. Types and classes
  4. Defining functions
  5. List comprehensions
  6. Recursive functions
  7. Higher-order functions
  8. Functional parsers
  9. Interactive programs
  10. Declaring types and classes
  11. The countdown problem
  12. Lazy evaluation
  13. Reasoning about programs

Je signale également le livre Haskell school of Expression, de Paul Hudak, pour ceux qui veulent utiliser la programmation fonctionnelle dans un contexte multimédia et artistique :

 

Paul Hudak que l’on peut voir dans cette vidéo, donnant une conférence sur « Haskell and the arts : How functionnal programmers can help, inspire or even be artists », enregistrée à Qcon San Fransisco en novembre 2008.

Enfin, la consécration, un ouvrage de référence chez O’reilly, le fameux Real World Haskell, que je déconseille toutefois avant d’avoir lu « Programming in Haskell » de Graham Hutton. On a ici un ouvrage mainstream, comme tant d’autres, mais fort utile pour faire du Haskell « dans la vraie vie ».

Sur les autres ressources, on ira sur Haksell.org, le portail qui rassemble toutes les infos utiles. À noter que depuis quelques mois un effort a été fait sur les packages d’installation avec The Haskell Platorm.

Pour les librairies on utilisera le génial Hoogle.

Côté des frameworks web, il y a Happstack, le plus ancien, mais aussi Snap qui, bien qu’en phase beta, semble jouir d’une bonne dynamique et donne des premières perspectives de performances intéressantes (ici les performances d’accès à des fichiers, plus est mieux):

Enfin, et pour terminer,  la petite blague sur Haskell qui a circulé sur Twitter, relativement à « l’évaluation paresseuse » (Lazy evaluation) dans Haskell, où les calculs ne sont effectués par le programme que s’ils sont nécessaires:

Put #Haskell on your resume even if you don’t know it. When asked, say your resume is lazy and you’ll learn it when results are needed.

Bonne initiation !

Hé hé, content de te voir intéressé par le sujet 🙂

À propos, la façon dont c’est écrit laisse penser que l' »évaluation paresseuse » et le « typage […] statique » font partie des « vertus de la programmation fonctionnelle ».

Sinon, j’aimerais bien savoir si tu comptes répondre à ton prochain appel d’offre en mettant Haskell en avant, ou même plus généralement la programmation fonctionnelle.

[Reply]

Oui bien sûr, j’ai même mis ton CV dans la propale 😉

Plus sérieusement, non. C’est pas une approche pour intégrateur ou DSI.

[Reply]

« Plus sérieusement, non. C’est pas une approche pour intégrateur ou DSI. » → pourquoi pas ?

[[ pour introduire progressivement des approches fonctionnelles dans ces langages ]] → c’est à mon avis le chemin que suivra l’industrie car pour l’instant, il y a un cruel manque de formation et de compétences dans le domaine.

Je pense que c’est l’intérêt des langages que tu appelles « hybrides ». C’est le choix que j’ai fait il y a quelques temps car j’ai dû me résoudre (comme toi) au pragmatisme. Et franchement, un langage comme Scala fait vraiment un bon boulot dans le genre !

Tout ça prendra du temps pour s’imposer, beaucoup de temps…

[Reply]

« Par nature, le programmeur Haskell à confiance dans son code alors que le développeur Java est dans une relation de méfiance. »

Je vais être cruel, mais je dirais que la plupart du temps, celui qu’on appelle « développeur Java » est arrivé là par hasard et n’a qu’une très faible idée de c’est qu’est le développement (dans le grand schéma des choses), alors que c’est quand même beaucoup moins souvent le cas en Haskell (raison n°1, sa confidentialité, n°2, là où on le trouve).

Le « développeur Java » est souvent dans une relation de méfiance parce qu’il considère que tout ce qu’il y a en-dehors de son code est magique, y compris le code écrit par son voisin de bureau. Ce qui en passant est dommage, vu qu’il n’y a pas « moins magique » que Java (comparé à C, C++, C#, Python, Ruby, Javascript…) étant donné la réticence de la plateforme à donner la main sur ce qui permettrait de truquer le comportement à l’exécution.

[Reply]

18 Oct 2010, 12:36
by GabrielKast

reply

Pour ce qui est du développeur Java, la situation est plus simple. Ils ne sont pas tous cons, mais plus simplement ils s’intègrent dans des projets ou des entreprises énormes, des systèmes qui dépassent l’entendement de ceux qui les concoivent. Java est assez simple pour être compréhensible par tout un chacun, et assez complexe pour faire de gros projets.
Java, c’est un peu comme l’anglais international.

Après, ce que dit Christian Fauré est que la programmation fonctionnelle permet d’avoir une confiance systématique dans son code parce que le langage est fait comme cela : typage, immutabilité… La preuve du fonctionnement et donc la confiance dans son propre code est structurelle et non pas subjective.

Je suis en train de passer de Java à Erlang grâce à mon apprentissage de Scala, qui m’a piqué au vif). Il n’y a pas de hasard mais un certain trend intéressant à mon avis.

[Reply]

Le papier « The Next Mainstream Programming Language: A Game Developer’s Perspective », from Tim Sweeney (Epic Games) est intéressant à lire : http://www.st.cs.uni-sb.de/edu/seminare/2005/advanced-fp/docs/sweeny.pdf

Vu les pbs de programmation des jeux, certains en sont même arrivés à se poser la question d’utiliser un langage comme Haskell. C’est dire si certains pbs logiciels croissants poussent de plus en plus les développeurs hors des sentiers (trop) battus.

Perso, je crois qu’ironiquement, la programmation fonctionnelle va s’imposer par effet de bord ! Ce que j’ai écrit dans « Functional programming on-going adoption as a side-effect » http://www.jroller.com/dmdevito/entry/functional_programming_on_going_adoption

Ce que je veux dire par là, c’est que l’adoption de la programmation fonctionnelle se fait incidemment, par petites touches, par évolution des langages existants qui font des emprunts aux langages fonctionnels. Ainsi, on peut espérer qu’un beau jour, après avoir jeté l’opprobre sur les langages fonctionnels, on va finir par s’apercevoir que l’on en utilise nombre de concepts un peu comme Mr Jourdain, et on s’apercevra que l’on a déjà traversé le rubicon.

Ainsi, les concepts de map/reduce initialement présents dans les langages fonctionnels sont repris dans pleins d’autres langages, et même dans JavaScript !
Et surtout, on voit arriver des langages qui mixent plusieurs paradigmes de programmation.
Perso, ce sont plutôt ces derniers, comme OCaml, qui ont ma préférence, car comme je ne crois pas trop à l’outil unique, je ne crois pas trop au paradigme unique.

[Reply]

Je vais juste revenir sur l’argument de l’évaluation paresseuse comme étant une optimisation.

L’évaluation paresseuse est une politique d’évaluation comme l’est le *call-by-value* mais qui, dans sa définition, n’a rien à voir avec une quelconque optimisation mais sur la sémantique qu’on donne à la manipulation des valeurs: les listes infinies est l’exemple le plus présenté pour comprendre cette notion d’évaluation paresseuse.

Maintenant, dans la pratique, il se trouve que l’évaluation paresseuse n’apporte aucun gain d’optimisation, au contraire, il demande au compilateur de gérer les valeurs comme des constructions associées à leurs environnements ce qui a un coût au niveau de la mémoire (puisqu’on a la construction et son environnement – alors que dans une politique *call-by-value* nous aurions directement la valeur) et au niveau du GC qui doit manager des objets plus complexe.

GHC fait donc des optimisations assez drastiques sur le code afin de se rapprocher des performances d’un langage comme OCaml – ce qui complexifie d’ailleurs l’inférence que l’on peut faire sur le code produit par GHC.

Après, il est vrai que __dans certains contextes__, il est plus efficace de déporter le calcul au plus tard pour certaines valeurs. Et c’est pour cette raison que l’évaluation paresseuse existe en OCaml mais elle n’est pas systématique.

Mais avoir cette politique par défaut complexifie vraiment toutes optimisations et c’est plutôt un handicap pour les performances pour peu qu’on ne sache pas maîtriser le comportement de GHC – on peut faire du code optimiser avec GHC mais il s’agira de connaître comment compile GHC.

PS: pour preuve, OCaml a récemment penser à faire une vraie passe d’optimisation mais pendant très longtemps, le compilateur produisait du code performant grâce aux axiomes qu’on peut émettre avec cette politique d’évaluation stricte.

[Reply]

Merci Dinosaure pour ce commentaire !

[Reply]

 

Répondre à Alexandre Bertails Annuler la réponse

Votre adresse e-mail ne sera pas publiée. Les champs obligatoires sont indiqués avec *

Ce site utilise Akismet pour réduire les indésirables. En savoir plus sur comment les données de vos commentaires sont utilisées.