19 points par GN⁺ 2024-09-13 | 3 commentaires | Partager sur WhatsApp
  • « Peu pratique », « académique », « de niche »

    • C’est la réaction des gens lorsqu’ils apprennent que mon langage de programmation préféré est Haskell
    • Je l’utilise non seulement pour des projets perso, mais aussi pour construire de vrais serveurs web
    • Je dirige chez Converge des équipes qui travaillent avec Haskell
  • Les idées reçues sur Haskell

    • Tout problème qu’un langage généraliste peut résoudre peut aussi l’être dans d’autres langages
    • De nombreuses fonctionnalités adoptées dans Python, Rust ou Typescript ont été inspirées par Haskell, ou y sont implémentées de façon plus robuste
    • Cela peut sembler être une variante de l’idéologie « choisissez une technologie ennuyeuse »
    • Il existe une idée fausse selon laquelle programmer n’est pas faire des maths, et qu’il faudrait donc exclure les éléments mathématiques
  • Objectif de cet article

    • Expliquer de manière rationnelle pourquoi Haskell est le meilleur choix pour la plupart des programmeurs
    • C’est particulièrement utile pour celles et ceux qui veulent produire du logiciel robuste de façon productive
    • L’article met aussi l’accent sur l’aspect amusant du développement logiciel
  • Désapprendre et réapprendre

    • La plupart des programmeurs sont habitués au paradigme impératif
    • Haskell est un langage purement fonctionnel, avec une courbe d’apprentissage abrupte
    • Le langage Haskell lui-même est facile à apprendre si l’on se limite à un sous-ensemble simple
    • La programmation fonctionnelle exige un changement complet dans la façon de construire les programmes
    • Ce processus aide à progresser en tant que programmeur
    • Citation d’Alan Perlis :

      Un langage qui n’influence pas votre manière de penser la programmation ne vaut pas la peine d’être connu.

Brève explication de la syntaxe

  • :: indique une signature de type (ex. : myThing :: String)

  • Un appel de fonction n’utilise pas de parenthèses ; on écrit les arguments après le nom de la fonction, séparés par des espaces (ex. : doSomething withThis withThat)

  • Dans une signature de type, une minuscule est une variable de type, qui représente un type arbitraire (ex. : head :: [a] -> a)

  • Il existe deux types de flèches, -> et => :

    • -> décrit le type d’une fonction (ex. : add1 :: Int -> Int)
    • => décrit une contrainte sur une variable de type et vient toujours en premier (ex. : add1 :: Num a => a -> a)
  • Les commentaires commencent par --

  • return est une fonction ordinaire et n’a pas le sens auquel on s’attend

  • do est du sucre syntaxique pour donner un aspect impératif

  • Il existe plusieurs façons d’affecter une valeur à une variable locale :

    let x = <something> in  
    <expression>  
    

    ou x <- <something>

  • Réduire les erreurs

    • Dans beaucoup de langages, on écrit de nombreux cas de test pour rendre le code « correct »
    • Haskell réduit fortement cette charge grâce à son système de types et à sa programmation purement fonctionnelle
    • Le système de types puissant de Haskell fournit des garanties concrètes sur le programme et les applique strictement
    • Caractéristiques du système de types :
      • Pas de types nullable
      • Possibilité d’exprimer des calculs qui peuvent échouer
      • Pattern matching et vérification d’exhaustivité
      • Évite gratuitement l’obsession des types primitifs
  • Les avantages de l’absence de valeur nulle

    • Comme la valeur null n’existe pas, on sait toujours si une valeur correspond au type attendu
    • Cela évite les erreurs à l’exécution et réduit la surface d’erreur
  • Exprimer des calculs susceptibles d’échouer

    • Les types Maybe et Either permettent d’exprimer explicitement les calculs qui peuvent échouer
    • Maybe représente un calcul dont le résultat peut exister ou non
      safeHead :: [a] -> Maybe a  
      
    • Either peut contenir deux types de valeurs (Left a ou Right b)
      validateAddress :: String -> Either AddressParseError ValidAddress  
      
  • Pattern matching et vérification d’exhaustivité

    • Il faut traiter tout le domaine des entrées, sinon le compilateur signale une erreur
    • Cela évite les erreurs à l’exécution et améliore la fiabilité du programme
  • Éviter l’obsession des types primitifs

    • newtype permet de créer facilement des types plus riches sémantiquement
    newtype VenueName = VenueName String  
    newtype EventName = EventName String  
    
  • Les avantages de la programmation purement fonctionnelle

    • Les données sont immuables et il n’y a pas à se soucier de mutations d’état
    • Les effets de bord sont gérés explicitement, et les fonctions ne dépendent que de leurs entrées, sans effets de bord
    • Cela améliore la prévisibilité et la stabilité du programme
  • Gestion explicite des effets de bord

    • La monade IO permet d’isoler et de contrôler les effets de bord dans le code
    • La signature de type d’une fonction permet de savoir qu’elle produit des effets de bord
    sendGreetings :: User -> IO Response  
    
  • Monades et contrôle des effets

    • Les typeclasses et les monades permettent d’encoder précisément les effets qu’une fonction peut produire
    • Cela évite les effets de bord involontaires et améliore la stabilité du code
  • Facteurs d’amélioration de la productivité

    • Le système de types puissant et la nature purement fonctionnelle facilitent la réutilisation du code et la généralisation des concepts
    • Des concepts comme Functor et Monoid permettent d’appliquer les mêmes motifs à différentes structures de données
    fmap (+2) [1, 2, 3] -- [3, 4, 5]  
    fmap (+2) (Just 2) -- Just 4  
    
  • Refactoring sans peur

    • Grâce à la rigueur du compilateur, modifier le code présente peu de risques d’introduire de nouveaux bugs
    • Le système de types permet d’exprimer précisément le domaine du programme, ce qui autorise des modifications en toute confiance
  • Mieux comprendre les programmes

    • La programmation déclarative permet d’exprimer précisément le domaine du problème
    • On peut plus facilement comprendre le sens du programme et accroître sa fiabilité
    • En supprimant la complexité inutile, on peut raisonner de manière saine sur le programme
  • Types de données algébriques et typeclasses

    • Il est possible de construire dans Haskell des langages spécialisés pour un domaine donné
    • Cela aide à comprendre et à maintenir les programmes
  • Exemple de programme

    • Un petit outil de comptabilité est écrit pour appliquer concrètement les concepts de Haskell

Épilogue

  • Utiliser Haskell est à la fois agréable et productif
  • La combinaison d’un système de types puissant et expressif avec la programmation purement fonctionnelle rend Haskell spécial
  • D’autres langages adoptent aussi ces fonctionnalités, mais dans Haskell elles sont au cœur du langage
  • Apprendre Haskell changera votre manière de penser la programmation

Avis de GN⁺

  • L’intérêt d’apprendre Haskell

    • Cela aide à élargir sa façon de penser en tant que programmeur
    • Comprendre le paradigme fonctionnel permet aussi d’écrire du meilleur code dans d’autres langages
  • L’essor de la programmation fonctionnelle

    • Elle est bien adaptée aux environnements informatiques modernes grâce à ses atouts en traitement parallèle et en concurrence
    • Le contrôle des effets de bord permet d’écrire du code prévisible
  • Comparaison avec d’autres langages

    • Il existe des langages qui prennent en charge la programmation fonctionnelle, comme Rust ou Scala, mais la pureté et le système de types de Haskell restent uniques
    • Les concepts de Haskell peuvent être utiles lors de l’apprentissage de nouveaux langages
  • Applicabilité en pratique

    • La courbe d’apprentissage initiale est raide, mais le gain de productivité compense le temps investi
    • C’est utile pour les systèmes complexes ou les domaines sensibles aux erreurs
  • Communauté et écosystème

    • La communauté Haskell est active, et de nombreuses bibliothèques et outils continuent d’être développés
    • Participer à des projets open source permet de progresser

3 commentaires

 
cosine20 2024-09-19

J’ai débuté avec F#, qui ajoute une touche de pragmatisme.

 
savvykang 2024-09-13

Les ADT et le filtrage par motifs, c’est bien, mais épargnez-nous les histoires de monades et de foncteurs.

 
GN⁺ 2024-09-13
Avis sur Hacker News
  • Haskell force à écrire des fonctions totales plutôt que des fonctions partielles

    • Haskell n’empêche pas la récursion infinie
    • Dans l’écosystème FP qui évolue vers les types dépendants, il est important d’empêcher le vérificateur de types de s’exécuter indéfiniment
    • Les nombreuses extensions ad hoc de Haskell causent des problèmes
    • Si l’on apprécie la philosophie de Haskell, il ne faut pas s’y limiter
    • La standardisation de Haskell a échoué
    • La proposition de valeur propre à GHC pourrait être le système d’exécution de GHC
  • J’utilise Haskell depuis 10 ans, et les outils se sont beaucoup améliorés

    • ghcup, le sandboxing de cabal et HLS sont stables
    • Je n’ai pas souvent constaté de manques dans l’écosystème des bibliothèques
    • Les temps de compilation de Haskell restent pénibles
    • Le temps de compilation des dépendances est long
  • Le système de types de Haskell ne prouve pas qu’une fonction est totale

    • Dans la programmation générale, prouver la totalité n’est pas très utile
    • La plupart des gens vérifient surtout qu’un programme fonctionne réellement à l’aide de tests
  • Le langage Haskell est bon, mais son écosystème a encore beaucoup de chemin à parcourir

    • Le compilateur est lent
    • Les capacités de rapport d’erreurs sont insuffisantes
    • La première erreur interrompt le reste de la compilation
    • Les outils restent insuffisants par rapport à d’autres langages fonctionnels
    • L’écosystème de bibliothèques est limité
    • Les idées de Haskell ont influencé de nombreux autres langages
  • J’aimerais utiliser Haskell ou un autre langage fonctionnel dans un cadre professionnel

    • Les langages comme Go étaient faciles à apprendre
    • J’aimerais apprendre à construire une base de code dans un langage fonctionnel
  • Haskell a eu un grand impact sur ma manière de penser la programmation et l’architecture du code

    • Le système de types de Haskell est très puissant et facile à comprendre
    • J’ai trouvé amusant de micro-optimiser du code Haskell
    • Les outils restent insuffisants
  • Haskell expérimente la paresse au niveau du langage

    • On peut obtenir la paresse au niveau de la bibliothèque standard
  • La pureté extrême et l’immuabilité de Haskell posent problème

    • Beaucoup de programmeurs trouvent plus simple d’exprimer des boucles procédurales/mutables
    • Rust utilise un système de types compétent et de nombreux idiomes fonctionnels, tout en permettant les boucles et la mutabilité
  • Haskell convient très bien aux logiciels de logique métier (BLOBS)

    • On peut modéliser la majeure partie de la logique métier avec des types simples et du pattern matching
    • En gardant les parties simples, il est facile de l’enseigner même à des contributeurs non techniques
    • Haskell est amusant