URL: https://linuxfr.org/news/sortie-du-glorious-haskell-compiler-7-8 Title: Sortie du Glorious Haskell Compiler 7.8 Authors: galbolle Piezo, BAud, Bruno Michel, Benoît Sibaud, tuiu pol, Lucas, ZeroHeure et claudex Date: 2014年04月01日T08:03:16+02:00 License: CC By-SA Tags: ghc, haskell et compilateur Score: 52 Ghc, le Glorious Haskell Compiler est sorti le 9 avril 2014 en version 7.8.1. Il s'agit du compilateur le plus populaire pour le langage Haskell. Haskell est un langage de programmation purement fonctionnel, avec un système de types sophistiqué. C'est le principal langage généraliste à utiliser une stratégie d'évaluation non-stricte par défaut : la valeur d'une expression n'est calculée que si elle est nécessaire. ---- [Tout sur Haskell](http://www.haskell.org) [« Apprendre Haskell vous fera le plus grand bien ! », une introduction à Haskell](http://lyah.haskell.fr/) [Les changements de la version 7.8.1](http://www.haskell.org/ghc/docs/7.8.1/html/users_guide/release-7-8-1.html) ---- # Haskell en trois mots Haskell est un langage de programmation purement fonctionnel, avec un typage statique fort, et une stratégie d'évaluation non stricte. Le _Glasgow Haskell Compiler_ est le principal compilateur Haskell, bien qu'il en existe d'autres. ## Quelques exemples L'inévitable _hello world_ : ```haskell main = putStrLn "Saluton Ĉirkaŭaĵojn!" ``` Suite de Fibonnacci : ```haskell fibs :: Int -> Int fibs 0 = 0 fibs 1 = 1 fibs n = fibs (n-1) + fibs (n-2) -- Sous forme de liste infinie fibs':: [Int] fibs' = 0:1:(zipWith (+) fibs' (tail fibs')) ``` ## Un langage fonctionnel pur La spécificité la plus marquante de Haskell, c'est qu'il s'agit d'un langage fonctionnel _pur_ : une fonction appelée avec les mêmes arguments renverra toujours le même résultat, contrairement à une fonction comme `input(message)` en python. Cela rend possible la _transparence référentielle_ : une expression peut être remplacée par son résultat sans changer le comportement de l'application. Le raisonnement sur les équations est mené par substitution sans inquiétude des effets de bord. Les entrée-sorties et autres effets de bord sont bien sûr possibles, mais ils sont distingués dans le système de type des calculs sans effets de bord. Cela permet des optimisations assez poussées et _garanties correctes_ sur ces derniers. Cette distinction des effets de bord dans le système de type est déroutante au début, mais avec l'expérience, elle apporte un réel confort. ## Avec un typage puissant Le typage statique permet de vérifier à la compilation la cohérence d'un programme et de détecter de nombreuses classes d'erreurs fréquentes. Un type statique est une approximation réalisée pendant la compilation des valeurs rencontrées au cours de l'exécution. Il est extrêmement difficile de concevoir un système de type à la fois flexible (faiblement verbeux, avec une inférence utile), complet (de grain fin, éliminant plus de bugs) et correct (pas de programmes justes rejetés). Haskell essaye de trouver le juste milieu pour que la programmation généraliste soit efficace. Les aficionados du typage dynamique et du « _duck typing_ » argumentent que, lors du développement avec les langages statiquement typés (typiquement C/C++), une grande partie des ressources sont gaspillées à combattre le système de type. Le typage statique de Haskell est rendu extrêmement flexible grâce au polymorphisme paramétrique, similaire aux _templates_ en C++, mais avec des possibilités d'inférence bien plus développées. Un type polymorphique peut être restreint à l'aide de contraintes, c'est-à-dire un ensemble de spécifications (ou _typeclasses_). Par exemple pour insérer un élément dans un `Set`, il est nécessaire de pouvoir le comparer aux éléments déjà présents avec la méthode `compare` de la _typeclasse_ `Ord`, d'où la contrainte `Ord a =>` dans le type de `insert` : ```haskell insert :: Ord a => a -> Set a -> Set a ``` En pratique, dans les cas courants, la seule différence induite par le système de types entre un code haskell et le code python correspondant est la présence (facultative mais habituelle) en haskell de la signature de chaque fonction... Signatures qui sont en cours d'adoption par la communauté python. # Les nouveautés de ghc 7.8.1 ## Changements du langage ### Typed holes Grâce au typage fort de haskell, on se trouve souvent à utiliser les types pour guider la conception : on écrit d'abord les types dont on va avoir besoin, puis les signatures des fonctions. Ensuite, de proche en proche, l'implémentation des fonctions est guidée par les signatures. Bien sûr, dans les cas les plus complexes, il faut d'autres ressources que cette méthode, mais on y devient rapidement accro. L'extension _typed holes_ (littéralement « trous typés ») permet d'utiliser cette démarche dans le corps d'une fonction. Cette extension est souvent utilisée conjointement avec le drapeau _-fdefer-type-errors_ qui transforme les erreurs de typage en warnings. Dans _ghci_, cela permet de charger toutes les définitions et de les manipuler même si leurs types sont incorrects. Une expression mal typée ou contenant des _typed holes_ est équivalant à _undefined_ et déclenchera une erreur uniquement si elle est évaluée. En pratique, un _hole_ est un `_` placé dans le code à la place d'une expression manquante (ici à la dernière ligne): ```haskell getSensorReading :: IO Double getSensorReading = return 123.45 -- TODO: utiliser vraiment la sonde thermique main = do tKelvins <- getSensorReading putStrLn ("Aujourd'hui il fait " ++ _ ( tKelvins - 273.15) ++ " degrés") ``` À la compilation, ghc émet une erreur (ou un warning si _-fdefer-type-errors_ est activé) pour chaque _hole_, et affiche son type: ``` Found hole ‘_’ with type: Double -> [Char] Relevant bindings include tKelvins :: Double (bound at toto.hs:6:5) main :: IO () (bound at toto.hs:5:1) In the expression: _ In the first argument of ‘(++)’, namely ‘_ (tKelvins - 273.15)’ In the second argument of ‘(++)’, namely ‘_ (tKelvins - 273.15) ++ " degrés"’ ``` Dans notre exemple, le _warning_ à la compilation nous indique que pour afficher la température dans le `putStrLn`, il nous faudra une fonction de type `Double -> String`. Une [simple recherche dans hoogle](http://www.haskell.org/hoogle/?hoogle=Double+-%3E+String+%2bbase) nous indique que la fonction en question n'est autre que `show`. ### OverloadedLists Haskell repose sur une syntaxe très concise, la majeure partie du langage (Opérateurs, type de base, etc) étant définie dans le _Prelude_. En revanche, ce n'est pas le cas des expressions littérales comme les nombres, les chaines de caractères et les listes. Par exemple ``[1, 2, 3]`` est interprété par le compilateur comme ``1:2:3:[]``, où ``(:)`` et ``[]`` sont les constructeurs du type liste défini dans le _Prelude_. [OverloadedStrings](http://www.haskell.org/ghc/docs/latest/html/users_guide/type-class-extensions.html#overloaded-strings) autorisait déjà les chaînes de caractères littérales avec d'autres types que ``[Char]``, notamment le type ``Text`` pour l'encodage UTF-8. Cette extension [OverloadedLists est documentée](http://www.haskell.org/ghc/docs/7.8.1/html/users_guide/type-class-extensions.html#overloaded-lists), elle permet d'utiliser la syntaxe des littéraux listes avec d'autres types, comme par exemple les vecteurs, les chaînes du module `Text` ou encore les ensembles. Pour utiliser cette extension, il faut disposer d'une instance de la classe `IsList`. Il faudra donc attendre que ces instances soient intégrées aux bibliothèques haskell pour vraiment en profiter. ### PatternSynonyms Une autre extension, [PatternSynonyms](http://www.haskell.org/ghc/docs/7.8.1/html/users_guide/syntax-extns.html#pattern-synonyms) permet de donner un nom à un motif pour le filtrage. La puissance des types de donnée algébrique (_ADT_) repose sur la possibilité de filtrer les données par motif, comme en Scala : ```haskell type Errno = Int data Error = ErrorLibC Errno | ErrorIO IOException errorToStr :: Error -> String errorToStr (ErrorIO ioe) = "Haskell's IOException: " ++ show ioe errorToStr (ErrorLibC errno) = "LibC's errno: " ++ show errno ``` Chaque constructeur du type ``Error`` défini un motif, utilisé par la fonction ``errorToStr`` pour filtrer les erreurs. En revanche il n'était pas possible de définir ses propres motifs en plus des constructeurs. _PatternSynonyms_ permet maintenant cela, par exemple pour avoir plusieurs motifs par constructeurs : ```haskell pattern ErrorPERM = ErrorLibC 1 pattern ErrorNOENT = ErrorLibC 2 pattern ErrorSRCH = ErrorLibC 3 errorToStr :: Error -> String errorToStr (ErrorIO ioe) = "Haskell's IOException: " ++ show ioe errorToStr ErrorPERM = "Operation not permitted" errorToStr ErrorNOENT = "No such file or directory" errorToStr ErrorSRCH = "No such process" errorToStr (ErrorLibC errno) = "LibC's unknown errno: " ++ show errno ``` Les motifs synonymes sont aussi utilisés pour cibler des données profondément imbriquées : ``pattern Greetings name = 'h':'e':'l':'l':'o':' ':name``. Par défaut il sont bidirectionnels : ``Greetings "world"`` est une valeur. Il est possible de définir des synonymes unidirectionnels lorsqu'il n'existe pas de bijection. ### TypeFamilies fermées Il est possible de déclarer une famille de type et ses instances dans la même clause, par exemple: ```haskell type family TF a where TF ([Bool]) = Int TF ([Bool],[Bool]) = Double ``` La famille est alors _fermée_, c'est-à-dire qu'il n'est pas possible de déclarer de nouvelles instances de `TF`. ## Améliorations du compilateur De nombreuses améliorations portent sur le compilateur lui-même, sans modifier le langage. Il est toujours plus rapide et économe en mémoire, notamment pour l'inférence de types. La compilation en parallèle de modules est activable avec la nouvelle option `-jN`. Sur Linux, FreeBSD et Mac OS X, `GHCi` utilise maintenant le chargeur de code dynamique du système. Auparavant, un chargeur maison liait dynamiquement du code statique (`.a`) en mémoire. Pour utiliser cette fonctionnalité, il est nécessaire de compiler avec ``-dynamic-too`` pour générer des bibliothèques dynamiques (``.dyn.so``). ### Améliorations de la génération de code La qualité du code que `ghc` produit s'améliore aussi : - `ghc` est capable d'utiliser plus de types «nus» (_unboxed_), avec l'activation de ``-funbox-small-strict-fields`` par défaut; - le gestionnaire d'entrée sortie se parallélise mieux, «de façon linéaire jusqu'à 32 cœurs»; - le nouveau générateur de représentation intermédiaire _Cmm_ a été activé, après une gestation de plusieurs années; - de nouvelles primitives (_PrimOps_) pour les instructions SIMD sont disponibles, pour l'instant uniquement avec le générateur LLVM. ### Amélioration du gestionnaire d'entrée-sorties Le gestionnaire d'entrée-sorties était un des points les plus critiques de la performance du _runtime_ haskell. Dans la version 7.8.1, il a été grandement amélioré, en particulier dans un contexte multi-processeurs. Haskell devient ainsi de plus en plus crédible comme _meilleur langage impératif du monde_. ### Compilation vers iOS La gestion de la compilation croisée a été améliorée, ce qui permet notamment de compiler vers les systèmes iOS. # Compilation vers javascript avec ghcjs La sortie de la version 7.8 devrait être accompagnée de la première version publique de `ghcjs`, un compilateur haskell vers javascript. Ce langage devient de plus en plus l'assembleur du client web et ghc prend ainsi en charge cette plateforme. Par rapport à [Fay](https://github.com/faylang/fay/wiki), qui est plus ancien, ghcjs cherche à compiler _tout le langage haskell_ et pas seulement un sous-ensemble. L'[introduction à ghcjs](http://weblog.luite.com/wordpress/?p=14) permet de se faire une bonne idée de la façon de l'utiliser, en particulier pour les parties spécifiques à javascript. # Vers ghc 7.10 La version 7.10.1 sera la prochaine version majeure de ghc. On trouve [sur le trac de ghc](https://ghc.haskell.org/trac/ghc/query?status=new&milestone=7.10.1&group=priority&col=id&col=summary&col=status&col=owner&col=type&col=priority&col=component&order=priority) une liste de choses qui devraient figurer dans cette prochaine version. Certaines nouveautés de cette version sont préparées dès la 7.8. ### Monad / Applicative Ces deux concepts permettent d'associer un effet à une valeur : `IO Int` peut par exemple représenter l'action de la lecture d'un entier présent dans un fichier. La notion de foncteur applicatif est plus générale : toutes les monades sont des foncteurs applicatifs, tandis que l'inverse n'est pas nécessairement vrai. L'exécution des effets d'une monade peut dépendre des valeurs obtenues des effets précédents, contrairement aux foncteurs applicatifs où les effets sont exécutés dans l'ordre des arguments. La classe de type _Monad_ fut introduite dans les premières versions du langage pour gérer les entrées/sorties avec la monade `IO`. Lorsque, plus tard, la classe de type _Applicative_ apparût dans la bibliothèque de base, _Monad_ n'a pas été modifiée pour avoir _Applicative_ comme super-classe. Le but de la [proposition _Functor_ < _Applicative_ < _Monad_](http://www.haskell.org/haskellwiki/Functor-Applicative-Monad_Proposal) est de corriger ce problème pour réduire la redondance (par exemple entre `return` et `pure`, `liftM` et `fmap`). Ce changement, susceptible de rendre du code incompatible, est déjà signalé par un warning dans GHC 7.8 et sera officialisé dans la version 7.10. # Autres actualités de haskell Olivier Charles a publié sur son blog [l'édition 2013 de sa chronique _24 Days of Hackage_](http://ocharles.org.uk/blog/pages/2013-12-01-24-days-of-hackage.html) qui offre une série d'introductions (avec des exemples) aux paquets majeurs disponibles sur Hackage. L'[édition 2012](http://ocharles.org.uk/blog/pages/2012-12-01-24-days-of-hackage.html) vaut également le détour, car elle couvre des paquets encore plus incontournables (base, containers, transformers, etc.). ## Hackage 2 Le site [hackage](http://hackage.haskell.org/) qui répertorie les paquets haskell libres, exécutables et bibliothèques est passé en version 2 en septembre 2013. L'aspect visuel a été amélioré, la recherche concerne maintenant aussi la description des paquets. La plupart des informations sont plus accessibles, en consultation mais aussi à la modification : le nouveau hackage est plus permissif, et il a une API rest plus étendue. D'autres fonctionnalités ont été développées mais pas encore déployées, comme la gestion flexible des tags et le calcul des dépendances inverses. ## Haskell platform Il n'est généralement pas recommandé d'installer ghc seul, mais plutôt de récupérer la [plateforme haskell](http://www.haskell.org/platform/), qui contient ghc ainsi que les bibliothèques les plus essentielles du monde haskell. Comme la version 7.8 de ghc a tardé, la plateforme n'a pas été mise à jour depuis la version 2013.2 de mai 2013. Une nouvelle version, adaptée à ghc 7.8 devrait sortir prochainement.