GHC 9.2 est sorti le 29 octobre 2021. Cette nouvelle version du principal compilateur pour Haskell apporte son lot de nouveautés détaillées dans la suite de cette dépêche.
Comme à notre habitude, nous terminerons la dépêche par un exemple de projet en Haskell.
Nous rappelons qu’Haskell est un langage de programmation qui se démarque par son design. En effet, fort d’un typage statique avec inférence (i.e. il n’est pas nécessaire d’écrire les types pour que le langage les vérifie), son évaluation paresseuse (le code n’est exécuté que quand c’est strictement nécessaire) et de sa séparation des effets, Haskell est un langage ovni dans le marché qu’il influence depuis de nombreuses années.
Sommaire
Notes de version
RecordDotSyntax et NoFieldSelectors
Les nouvelles extensions OverloadedRecordDot
NoFieldSelectors
, OverloadedRecordUpdate
ainsi que le support de DuplicateRecordFields
avec l’extension PatternSynonyms
impactent un point important du langage : la syntaxe des records.
Pour comprendre celui-ci, ainsi que son impact potentiel sur le langage, il faut un peu de contexte.
Records
Haskell permet de définir des records, c’est-à-dire des types ayant plusieurs champs nommés. Par exemple :
data Joueur = Joueur {
nom :: String,
score :: Int
} deriving (Show)
La création, mise à jour et lecture des champs d’un Joueur
se font de la façon suivante, ici dans une session interactive :
>>> unJoueur = Joueur { nom = "Guillaume", score = 9001 }
>>> unJoueur
Joueur {nom = "Guillaume", score = 9001}
>>> -- Update
>>> unAutreJoueur = unJoueur { score = 10000 }
>>> unAutreJoueur
Joueur {nom = "Guillaume", score = 10000}
>>> -- Lecture d’un champ
>>> score unAutreJoueur
10000
On rappelle que Haskell est un langage qui privilégie la non mutabilité, c’est-à-dire que l’on ne peut pas modifier unJoueur
, il faut donc créer une nouvelle valeur unAutreJoueur
à chaque mise à jour.
Cette syntaxe de record possède de nombreuses limitations.
- Les lectures et mises à jour sur des structures profondes sont généralement complexes. Par exemple, en imaginant que notre joueur est stocké dans le champ joueur
d’une autre variable jeu
, si on veut mettre à jour le score de notre joueur, il faudra écrire :
nouveauJeu = jeu {
joueur1 = joueur1 jeu {
score = score (joueur1 jeu) + 1
}
}
C’est extrêmement verbeux.
La création d’un type (ici
Joueur
) va créer autant de fonctions qu’il y a de champs. Dans notre exemple précédent, les fonctionsnom
etscore
seront créées. Cela génère quantité de fonctions qui peuvent entrer en conflit avec d’autres fonctions (comme la fonctionid
).Le langage Haskell ne permet pas, par défaut, que deux types différents aient les mêmes noms de champs. L’extension
DuplicateRecordFields
supprime cette limitation, cependant les mises à jour et accès aux champs peuvent rester ambigus dans certaines situations.Il n’est pas possible de réaliser des fonctions polymorphiques sur les noms de champs. Ainsi, imaginons la fonction suivante:
afficherNom obj = nom obj
On pourrait imaginer que, de façon similaire à Python, ou C++, cette fonction puisse accepter n’importe quel objet à condition qu’il ait un attribut nom
. Hé bien non, cette fonction est ambiguë et le développeur devra choisir et implémenter autant de fonctions qu’il veut gérer de types différents, même si ces fonctions sont toutes les mêmes.
Un début de solution, lens
Les « lens » sont un ensemble de fonctionnalités qui permettent la manipulation de « chemins » dans des structures de données, puis l’utilisation de ces chemins pour lire (view
), modifier (over
) ou écraser (set
) une donnée.
Le problème est qu’il faut manuellement définir des « lens » pour chacun des champs auxquels on souhaite accéder. La librairie lens
propose de réaliser cela par le biais de TemplateHaskell
.
data Joueur = Joueur {
_score :: Int,
_nom :: String
} deriving (Show)
makeLenses ''Joueur
data Jeu = Jeu {
_joueur1 :: Joueur,
_joueur2 :: Joueur
} deriving (Show)
makeLenses ''Jeu
makeLenses
va générer les lens score
, nom
, joueur1
et joueur2
.
Maintenant on peut faire des choses :
>>> unJeu = Jeu { _joueur1 = Joueur { _score = 0, _nom = "Guillaume"}, _joueur2 = Joueur { _score = 0, _nom = "Valérian" }}
>>> unJeu
Jeu {_joueur1 = Joueur {_score = 0, _nom = "Guillaume"}, _joueur2 = Joueur {_score = 0, _nom = "Val33rian"}}
>>> view (joueur1 . score) unJeu
0
>>> unJeu' = set (joueur1 . score) 100 unJeu
>>> view (joueur1 . score) unJeu'
100
>>> unJeu'' = over (joueur1 . score) (*2) unJeu'
>>> unJeu'
Jeu {_joueur1 = Joueur {_score = 100, _nom = "Guillaume"}, _joueur2 = Joueur {_score = 0, _nom = "Val33rian"}}
Les « lens » règlent le problème de la modification en profondeur d’une structure de donnée, cependant les problèmes de conflit de nom et de mises à jour polymorphiques restent.
De plus s’ajoute un nouveau problème. Il existe de nombreuses librairies de lens, avec des approches différentes. On peut citer lens
et optics
. Ces librairies sont impressionnantes de fonctionnalités (bien que l’on puisse se limiter au sous-ensemble que je viens de présenter), les erreurs du compilateur peuvent être dures à lire.
« Generic-lens »
Le paquet generic-lens (et ses variantes pour d’autres type de lens, comme generic-optics) permettent de générer des lens avec une syntaxe différente. Là où le package précédent générait une lens dans l’espace de nom des fonctions (e.g. score
dans l’exemple d’avant), ces nouveaux packages permettent de créer des lens en utilisant des chaînes de caractère au niveau du type field @"joueur1
ou des « labels », #joueur1
.
La lens joueur1 . score
devient alors field @"joueur1" . field @"score"
ou #joueur1 . #score
.
L’avantage de cette approche est qu’il n’y a plus de conflit d’espace de nom et que les lens peuvent être polymorphiques, c’est-à-dire s’appliquer sur le même champ de type différent.
Les inconvénients de ces approches sont les suivants :
- la syntaxe est soit « verbeuse » (
field @"joueur1
), ou utilise les labels (e.g.#joueur1
), nécessitantOverloadedLabels
, qui est une syntaxe assez récente dans GHC. Celle-ci est peu utilisée, mal connue, la syntaxe est nouvelle et elle pose son lot de problème. Par exemple, avec la librairelens
, les labels génèrent des instances orphelines. Ce n’est pas le cas avec la bibliothèqueoptics
. - Cela demande le choix de l’utilisation d’une bibliothèque de lens, ce qui limite l’adoption.
- GHC va toujours créer les fonctions pour nos sélecteurs. Ainsi, deux types ayant les mêmes noms de champs vont générer les mêmes sélecteurs et ainsi générer des conflits, même si ceux-ci ne sont pas utilisés.
RecordDotSyntax
et NoFieldSelectors
L’extension NoFieldSelectors
permet tout simplement de ne plus exposer les sélecteurs associés aux champs d’un type. Cela supprime tout simplement les problèmes de conflits discutés avant.
Les extensions OverloadedRecordDot
et OverloadedRecordUpdate
permettent tout simplement d’utiliser une syntaxe assez classique dans d’autres langages de programmation, le .
, pour accéder aux champs.
Ainsi, accéder au champ nom
du joueur1
du jeu
se fait grâce à jeu.joueur1.nom
. Et la mise à jour en profondeur est aussi possible, par exemple:
nouveauJeu = jeu {
joueur1.score = jeu.joueur1.score + 1
}
OverloadedRecordUpdate
ne permet pas (encore) de mise à jour pouvant changer le type d’un sous champs (ce qui est possible avec les « lens »), et la syntaxe reste plus lourd que les lens dans le cas de mise à jour profonde, comparez l’exemple précédent avec :
nouveauJeu = over (#joueur1 . #score) (+1) jeu
De plus, OverloadedRecordUpdate
nécessite que l’utilisateur fournisse une fonction setField
et getField
, ainsi cela ne fonctionne pas encore directement. Gageons que de futures versions de GHC fourniront des fonctions adaptées par défaut.
Conclusion
Les lens en général restent plus puissantes que cette extension, et la librarie optics
, avec les labels et l’absence de conflit de nom grâce à NoFieldSelectors
apportent à mon gout plus de souplesse.
Cependant l’arrivée de ces changements au niveau des records en Haskell apportent une solution « officielle » aux problèmes des record et devrait simplifier l’adoption d’Haskell par les débutants, c’est donc à mon avis une très bonne nouvelle.
GHC 2021
Vous le savez sans doute, GHC introduit des nouveautés vis-à-vis du standard Haskell par le biais d’extension.
Malheureusement ce mécanisme devient ingérable tant la liste d’extensions est longue. Chaque fichier Haskell commence généralement par une liste de multiples extensions, les développeurs hésitent à activer certaines d’entre elles. Pour exemple, l’utilisation de syntaxes 0b01
et 0xfe
pour représenter des nombres respectivement en notation binaire ou hexadécimale, nécessitent l’activation de deux extensions.
La nouvelle extension, GHC2021
regroupe tout un ensemble d’extensions, 46 au total et devrait réduire le préambule des fichiers dans un projet.
Le processus qui a permis de sélectionner ces extensions est particulièrement intéressant. Chaque extension du langage a été notée en fonction de différents critères tels que son utilisation par la communauté, le risque de « surprise », l’apport au langage…
En vrac
Types liftés
- l’extension
UnliftedDataTypes
permet de définir des types qui n’acceptent pas d’évaluation paresseuse. Il était déjà possible de forcer l’évaluation par le biais deBangPatterns
ou deStrict
etStrictData
, mais ces extensions n’avaient pas d’impact sur la représentation des données. La nouvelle extensionUnliftedDataTypes
permet ainsi de créer des types n’acceptant pas d’évaluation paresseuse, et ainsi, dans certains cas, de réduire leur taille. Cela sera très utile dans certaines structures de données afin de réduire les indirections de pointeurs qui coûtent en performance. - lié au point précédent, la représentation des types « lifted » ou « unlifted » (i.e. acceptant ou non une version paresseuse et étant oui ou non géré par le ramasse-miette) évolue et permet de représenter des fonctions polymorphiques quelle que soit la représentation des objets utilisée.
Ces deux points vont dans le sens de générer du code plus efficace avec moins d’indirection (i.e. UnliftedDataTypes
) sans payer le coût d’une double implémentation grâce aux fonctions polymorphiques sur la représentation.
-
ghc-exactprint
est fusionné dans GHC. La représentation du code après parsing conserve les informations de présentation tel que les espaces blancs, les retours à la ligne, etc. Ainsi il est possible de parser du code Haskell, faire des modifications, et réécrire ce code sans changer la présentation. C’est une grosse avancée pour l’outillage puisque, par exemple, cela améliore l’intégration avec les outils de refactoring d’un IDE qui peuvent maintenant transformer le code (par exemple renommer une variable) sans changer la présentation du code. Il est maintenant possible de générer de la documentation par le biais de
TemplateHaskell
. En effet,TemplateHaskell
permet la génération de code pendant la compilation, mais jusqu’à alors, ce code ne pouvait pas être associé à une documentation, c’est maintenant corrigé grâce aux fonctionsputDoc
etgetDoc
qui permettent respectivement de générer une documentation ou de lire une documentation.l’extension
ImpredicativeTypes
a été complètement revue et est maintenant considérée comme robuste. C’est un détail assez complexe du langage invisible pour beaucoup, mais sachez que cela permet l’instanciation de fonctions plus polymorphiques et que cela impacte un opérateur utilisé tous les jours par les développeurs Haskell, `{mathjax}
, qui n’est autre que l’application de fonction (e.g.f x
etf
x` sont identiques). En bref, un cas particulier du langage est maintenant géré de manière robuste et sans cas particulier. Je vous renvoie vers l’article qui traite de cela, https://www.microsoft.com/en-us/research/publication/a-quick-look-at-impredicativity/.Un générateur de code natif pour AArch64 est maintenant disponible. Aarch64 était déjà géré par GHC par le biais du backend LLVM, mais le générateur de code natif est plus rapide.
LinearTypes
peut maintenant inférer la multiplicité dans les expressionscase
. Dit autrement, on peut utiliser descase
avec les types linéaires, ce qui n’était pas possible auparavant, l’algorithme n’arrivant pas à « compter » correctement l’usage des références.Un nouveau warning
-Wredundant-bang-patterns
prévient lors de l’usage inutile d’un bang (i.e.!
) sur une donnée qui est déjà forcée. Ce n’est pas forcément utile, mais cela peut donner une meilleure compréhension du code.Le type
Natural
peut maintenant être promu au niveau du "kind", remplaçant le kindNat
qui existait avant.Natural
représente un entier positif.Nat
permettait de représenter un entier positif paramétrant un type. Par exemple, le kindMatrix (a :: Nat) (b :: Nat)
, permet de représenter par exemple le typeMatrix 4 4
, où4
est un nombre entier positif, mais connu dans le type et non pas seulement à l’exécution. La convergence entreNatural
etNat
permet d’écrire des types qui seront utilisés autant à l’exécution qu’en tant que kind.Le type
Char
peut maintenant aussi être promu au niveau du "kind" et de nouvelles "types families" (i.e. fonctions de type) permettent de composer desChar
ensemble afin de construire desSymbol
(i.e. des chaines de caractère au niveau du type). Cela ouvre tout un tas de perspectives de programmation au niveau du type.
Debug
Beaucoup de changements de fond qui vont permettre d’améliorer le processus de debug d’un programme arrivent avec GHC 9.2.
Origine des allocations
La méthode de hi-profiling
permet de tagger les objets lors de leur allocation en précisant l’origine de l’allocation. Ainsi, lors de l’exécution, il est possible de savoir d’où viennent les objets encore présents en mémoire.
Jusqu’à présent il était possible de connaitre l’usage de la mémoire par type d’objet ou le nombre d’allocation par origine dans le code. Mais une fonction qui alloue beaucoup n’est pas forcément une fonction qui utilise beaucoup de mémoire, si les objets alloués ont une durée de vie courte.
Plus de détails dans l’article https://well-typed.com/blog/2021/01/first-look-at-hi-profiling-mode/
ghc-debug
http://ghc.gitlab.haskell.org/ghc-debug/ permet de se connecter à un programme Haskell en cours d’exécution et d’interroger l’état de la mémoire. Jusqu’à présent, les analyses de mémoire ne pouvaient se faire que statiquement, à la fin de l’exécution du programme.
Performances
GC Parallel
Le GC (Garbage Collector) parallèle a subi de nombreux changements. Sur les programmes parallèles tournant sur plus de 4 "capabilities" (e.g. threads), les temps de pause et le temps CPU utilisé par le GC sont réduits.
C’est une avancée importante pour le GC parallèle qui demandait avant beaucoup de réglages manuels pour trouver les paramètres optimaux. Les développeurs de GHC vont jusqu’à annoncer que la plupart des réglages manuels utilisés avant sont inutiles et que les valeurs par défaut seront satisfaisantes dans la plupart des cas.
Personnellement, j’attends de tester cela en production puisque jusqu’à présent, j’avais bien trop souvent tendance à désactiver totalement le GC parallèle du fait de ses mauvaises performances.
Autres
- Un programme Haskell aura tendance à rendre plus vite la RAM inutilisée au système, plutôt que de la conserver. L’impact est faible (puisque la RAM inutilisée pouvait être mise dans le SWAP), mais cela peut améliorer la « confiance » en un processus Haskell qui, une fois un pic de consommation passé, affichera une consommation réduite.
- La taille de la nurserie par défaut passe de 1 MB à 4 MB. Cette valeur faisait du sens plusieurs années en arrière lorsque la taille des caches des CPUs était plus petite. On rappelle que la nurserie est l’endroit ou les objets sont alloués (avant d’être potentiellement déplacés), c’est donc un endroit sous haute pression qui vit dans le cache du processeur, l’augmenter à 4MB permet d’allouer plus d’objets avant de devoir faire tourner le GC, laissant une plus grande chance aux objets temporaires d’être détruits et ainsi améliorant les performances.
Autour de GHC
Haskell-language-server, https://hackage.haskell.org/package/haskell-language-server, le LSP pour Haskell est sorti en version 1.4.
Exemple
Dans cette section, je voulais parler un peu de formatage.
Haskell et le formatage
En Haskell, le formatage est une histoire complexe.
Au départ, on fait tout à la main:
>>> prenom = "Guillaume"
>>> age = 35
-> >>> putStrLn ("Bonjour " <> prenom <> ". Tu as " <> show age <> " ans.")
Bonjour Guillaume. Tu as 35 ans.
On admettra que cela est peu pratique. C’est difficilement lisible. On se trompe facilement en oubliant un espace. Et on ne peut pas faire de conversion facilement, comme préciser le nombre de chiffres significatifs.
La libraire base
, qui vient de base avec GHC, propose Text.Printf
:
>>> >>> printf "Bonjour %s. Tu as %d ans.\n" prenom age
Bonjour Guillaume. Tu as 35 ans.
C’est pratique, cela rend quelques services et cela permet de formater:
>>> printf "%.3f\n" pi
3.142
Mais cette bibliothèque souffre de nombreux défauts, et tout particulièrement:
- Pas de support des chaines de plusieurs lignes.
- Par défaut, cela génère des
String
, dans un monde ou on aimerait plutôt utiliserText
-
printf
n’est pas sûr et ainsi peut planter lors de l’exécution :
>>> printf "%s" pi
*** Exception: printf: bad formatting char 's'
Il existe de nombreuses librairies qui proposent des « mini langages » sous forme de fonctions pour faire du formatage. J’apprécie fmt, mais cela reste très verbeux:
>>> let (a, b, n) = ("foo", "bar", 25)
>>> ("Here are some words: "+|a|+", "+|b|+"\nAlso a number: "+|n|+"") :: String
"Here are some words: foo, bar\nAlso a number: 25"
Et cela ne corrige pas le problème des lignes multiples.
Comment fait Python ?
Avec Python, c’est simple, il existe les f
string:
>>> f"Bonjour {prenom}. Tu as {age} ans. Et pi = {pi:.3f}."
'Bonjour Guillaume. Tu as 35 ans. Et pi = 3.141.'
C’est simple, c’est lisible, cela permet le formatage avancé, cela permet les lignes multiples. Seul défaut, c’est du Python et ce n’est pas sûr.
PyF
PyF c’est ma libraire de formatage pour Haskell. J’ai pris les f
string de Python, j’y ai ajouté le côté vérifié à la compilation, et on obtient PyF :
>>> [fmt|Bonjour {prenom}. Tu as {age} ans. Et pi = {pi:.3f}.|]
"Bonjour Guillaume. Tu as 35 ans. Et pi = 3.141."
PyF supporte la quasi-totalité du mini langage de formatage des f string de Python.
La dernière version, qui sort en même temps que GHC 9.2, a considérablement réduit ses dépendances et ne dépendant maintenant plus que de GHC
. De plus, de nouveaux formateurs sont apparus :
-
str
: une chaîne multi lignes sans formatage -
raw
: une chaîne multi lignes sans échappement -
strTrim
etfmtTrim
, respectivement une chaîne multi lignes sans et avec formatage, mais avec suppression des espaces blancs dans les deux cas.
Les versions trim
sont tout particulièrement utiles pour respecter l’indentation dans un code :
main = do
putStrLn [fmtTrim|
Bonjour {nom},
Voici ma liste de course :
- Poivrons {nombreDePoivrons}
- Lait {volumeDeLait:.1f}
|]
Ici, les espaces blancs surnuméraires seront supprimés.
Conclusion
GHC 9.2 est là, happy Haskelling.
Vous pouvez utiliser nix
, ou ghcup
, ou prochainement votre distribution. Ou peut-être un container docker, ou stack
, bref, essayez GHC 9.2.
J'ai tout particulièrement envie de tester :
- les meilleures performances du ramasse-miette parallèle ;
-
NoFieldSelector
pour ne plus avoir de conflit de nom ; -
GHC2021
pour ne plus commencer tous mes programmes Haskell par 40 lignes d’extensions ; -
ghc-debug
pour debuger.
Mais je dirais que je suis un utilisateur avancé. J’ai vraiment hâte de voir comment les changements sur les records vont aider les débutants à s’approprier Haskell.
Aller plus loin
- GHC 9.2.1-alpha2 now available (26 clics)
- Note de version (19 clics)
- Annonce de version (18 clics)
# Coquilles
Posté par Guillaum (site web personnel) . Évalué à 6.
Est-ce que quelqu'une de la fine équipe de modératisation pourrait corriger les points suivants :
Remplacer le
{mathjax}
par$
et l'exemple qui suit par :"
) ont été remplacés sauvagements par des symboles cabalistiques («
) ce qui casse la coloration syntaxique.Merci beaucoup.
[^] # Re: Coquilles
Posté par Ysabeau 🧶 (site web personnel, Mastodon) . Évalué à 4.
Corrigé pour la deuxième série pour laquelle je plaide coupable. En effet j’étais en train de relire et corriger avec Grammalecte quand la dépêche a été publiée. Du coup, cette bourde que je devais corriger a été oubliée dans la série de petites corrections qui restaient à faire (espaces avant les ponctuations doubles par exemple).
C’est quelque chose qui ne devrait pas arriver, qu’une dépêche en cours de correction soit publiée. Il a été suggéré dans la tribune de modération que « le coupable doive faire le tour du quartier tout nu et passer une semaine sous Windows 11 ? ».
Une semaine sous Windows 11 me paraît un châtiment bien trop fort pour ça (et je ne tiens pas personnellement à assister à l’autre partie de la sentence).
Sinon, à titre indicatif, ceci : « », ce sont des guillemets typographiques (unicode ab et bb), et ça ‟ ” (unicode 201f et 201d) ce sont des guillemets anglais (il y en a plus). Ça : " (unicode 22) c’est juste une cochonnerie, bonne pour le code mais pour rien d’autre et qu’on appelle une chiure de mouche en typographie (pareil pour ça : ' qui n’a rien à voir avec l’élégante apostrophe typographique ’, code unicode 2019).
Je n’ai pas trouvé ça : {mathjax}.
« Tak ne veut pas quʼon pense à lui, il veut quʼon pense », Terry Pratchett, Déraillé.
[^] # Re: Coquilles
Posté par Guillaum (site web personnel) . Évalué à 2.
Merci pour les corrections.
Il reste toujours les problèmes avec
f x
etf $ x
etmathjax
, mais cela n’apparaît surement que dans la version finale et pas dans le code markdown d'origine.Et pour les guillemets, merci pour les précisions.
[^] # Re: Coquilles
Posté par Ysabeau 🧶 (site web personnel, Mastodon) . Évalué à 2.
Oui c'est tout à fait ça.
Quoi que j'essaie comme graphie, le symbole dollar $ sème la zone dans cette façon d’écrire :-( Apparemment si ce symbole est encadré par des virgules, des apostrophes ou des parenthèses il est transformé en autre chose.
Exemple : Haskell, le symbole du dollar f x
et
fx
sont identiques).On pourrait rédiger ainsi : Haskell, le symbole du dollar qui n’est autre que l’application de fonction, ainsi, on peut écrire
fx
avec sans le $ entre f et x (fx = f$x).« Tak ne veut pas quʼon pense à lui, il veut quʼon pense », Terry Pratchett, Déraillé.
[^] # Re: Coquilles
Posté par Gil Cot ✔ (site web personnel, Mastodon) . Évalué à 2.
Je me souviens avoir discuté de ça à un autre propos : c'est le parseur Markdown qui détecte une expression mathématique malgré tout ce qu'on fait. C'est inhérent au format et aux extensions ajoutées. Le seul contournement serait alors d'utiliser les blocs de code (ce qui au passage offrira la coloration en bonus.)
À voir s'il faut faire une entrée de suivi pour cela ; je n'avais pas jugé la chose nécessaire.
“It is seldom that liberty of any kind is lost all at once.” ― David Hume
[^] # Re: Coquilles
Posté par Ysabeau 🧶 (site web personnel, Mastodon) . Évalué à 2. Dernière modification le 06 novembre 2021 à 17:29.
Pour l’entrée de suivi, si ce n'’est pas du ressort de LinuxFr, ça ne servira pa à grand je pense. J’ai hésité aussi d'ailleurs. Je pense que c’est plus une info à ajouter dans l'aide sur la syntaxe Markdown de LinuxFr.
On pourrait aussi rédiger le truc problématique ainsi :
Je ne vois, en effet, pas d'autre solution.
La coloration syntaxique n’a aucune importance dans ce cas précis.
« Tak ne veut pas quʼon pense à lui, il veut quʼon pense », Terry Pratchett, Déraillé.
[^] # Re: Coquilles
Posté par Gil Cot ✔ (site web personnel, Mastodon) . Évalué à 3. Dernière modification le 06 novembre 2021 à 17:45.
En fait il y a un peu des deux… Markdown est lui-même limité (d'où divers ajouts incompatibles entre les uns et les autres) et assez fragile (encore plus avec les ajouts). Linuxfr a ses ajouts/extensions qui interfèrent visiblement ici.
L'aide à la rédaction, en bas de la fenêtre de commentaire, indique bien la possibilité de rajouter des formules/expressions mathématiques et des/la symboles/notation LaTeX entre dollar et dollar (avec l'exemple ) Bien. Ou entre doubles dollars (avec l'exemple $$) Moins bien visiblement.
Le souci, est que si je recopie un texte avec deux mentions de prix, par exemple un truc qui coûterait entre sept et neuf dollars (en écrivant « in range $7—$9 » par exemple) ça ne marche heureusement pas (le côté fragile et imprévisible que j'évoquais) Par contre, ça part visiblement en vrille quand on passe en code en ligne (comme dans le cas de «
f$x
et f$x » alors que le mode code devrait être protégé d'un côté et qu'il n'y a pas les deux dollars de l'autre)Sinon j'ai retrouvé le cas auquel j'ai été confronté : https://linuxfr.org/forums/programmation-shell/posts/sollicitation#comment-1866687
Je n'ai finalement pas fait de suivi car c'est difficile à décrire et bien circoncire (comment résoudre un problème qu'on n'arrive pas à bien poser ?) En tout cas pour moi. Je remarque juste de temps en temps des anomalies que j'arrive à contourner ou pas.
“It is seldom that liberty of any kind is lost all at once.” ― David Hume
[^] # Re: Coquilles
Posté par Frédéric Blanc . Évalué à 1.
Pour moi il y a aussi une coquille ici :
Je pense que l'auteur parle de la taille des caches, donc il faut un singulier et non un pluriel : «lorsque la taille des caches des CPUs était plus petite».
[^] # Re: Coquilles
Posté par Ysabeau 🧶 (site web personnel, Mastodon) . Évalué à 3.
Corrigé, merci (et « il y a quelques années » serait préférable à « plusieurs années en arrière » qui est un pur anglicisme).
« Tak ne veut pas quʼon pense à lui, il veut quʼon pense », Terry Pratchett, Déraillé.
[^] # Re: Coquilles
Posté par Frédéric Blanc . Évalué à 3.
Si on veut se lancer dans le nettoyage des anglicismes, toujours dans la même phrase, il y a aussi «Cette valeur faisait du sens» («faire (du) sens» étant le calque de l'anglais ‟make sense”, alors qu'en français on parle d'«avoir du sens»).
[^] # Re: Coquilles
Posté par Anthony Jaguenaud . Évalué à 4.
Hello Guillaum,
Très belle dépêche, comme d’habitude.
Serait-il possible d’ajouter ce qu’est le
Haskell-language-server
et à quoi ça sert ? En suivant les liens, j’ai l’impression que ça permet de mettre des tests dans les commentaires, mais sinon, je n’ai pas tout compris.[^] # Re: Coquilles
Posté par barmic 🦦 . Évalué à 4.
C'est ce LSP là dont il est question : https://linuxfr.org/news/lsp-le-cadeau-de-microsoft
https://linuxfr.org/users/barmic/journaux/y-en-a-marre-de-ce-gros-troll
[^] # Re: Coquilles
Posté par Anthony Jaguenaud . Évalué à 2.
Merci pour l’explication.
J’avoue qu’une extension de l’accronyme avec un lien Wiki aurait pu être sympas.
[^] # Re: Coquilles
Posté par Guillaum (site web personnel) . Évalué à 2.
Merci !;)
Et désolé, j'ai un peu torché cette partie de la dépêche sur
haskell-language-server
. Mais en gros cela apporte tous les trucs considerés comme "de base" dans des éditeurs avancés pour des langages classiques.Bref, des année que je jalousais les devs C++ dans visual studio, j'ai maintenant la même chose dans vim avec Haskell:
Et le plus intéressant c'est que tu peux faire des plugins maison, et donc ajouter n'importe quoi qui soit intéressant seulement pour ton business.
Je m'en sers sur tous mes projets persos depuis plus d'un an et j'ai mis en place le support (avec bazel ;() dans mes deux derniers boulots et cela marche très bien, sauf qu'il faut une machine avec beaucoup de RAM sur des projets conséquents.
# Histoire
Posté par barmic 🦦 . Évalué à 4.
Quelle partie d'haskell a une histoire simple ? 🙂
https://linuxfr.org/users/barmic/journaux/y-en-a-marre-de-ce-gros-troll
[^] # Re: Histoire
Posté par Guillaum (site web personnel) . Évalué à 2.
;)
L'histoire de tout est complexe, mais en effet, certains points en Haskell ont encore une histoire complexe (par exemple, le formatting ou les records). Mais j'espere que leur histoire complexe deviennent une histoire simple dans le futur (grace à PyY et GHC 9.2)
# Sûreté
Posté par Pol' uX (site web personnel) . Évalué à 4.
Ça semble un peu gratuit, lâché comme ça. Tu veux expliquer en quoi ton format et plus sûr que le format de python ?
Adhérer à l'April, ça vous tente ?
[^] # Re: Sûreté
Posté par barmic 🦦 . Évalué à 4.
Pas besoin d'aller très loin ;) Chaînes de formatage et sécurité en python (solution au "Petit Défi Python")
https://linuxfr.org/users/barmic/journaux/y-en-a-marre-de-ce-gros-troll
[^] # Re: Sûreté
Posté par Guillaum (site web personnel) . Évalué à 4.
Merci, je redécouvre ce comportement.
Même si PyF ne peut pas "injecter" du comportement ou lire une variable non prévue, PyF n'est pas protégé d'un formatage dangereux. Par exemple, en spécifiant une "précision" très grande pour un nombre, on va se retrouver avec une grosse occupation mémoire (e.g. la chaîne générée sera longue), ce qui peut sans doute être exploité pour tuer un service.
Bref, même en Haskell, il ne faut pas faire confiance aux valeurs qui viennent de l'exterieur.
[^] # Re: Sûreté
Posté par Guillaum (site web personnel) . Évalué à 10.
Merci pour cette question, en effet cela demande des précisions.
En premier lieu, "mon" format n'est pas plus sûr que le format de python, c'est le même format. Plus exactement, un sous ensemble.
La réponse de barmic est un cas extrême d'exploitation du coté dynamique de python. Mais j'avoue que je ne pensais même pas à cela en rédigeant ce paragraphe.
Je parlais de "sûreté" au sens "typage".
En pratique, le formatage de chaîne python est réalisé dynamiquement : lors de l’exécution, l’interpréteur python va construire la chaîne de formatage, interpréter celle-ci et y insérer les différents expressions / valeurs nécessaire. À ce moment, il peut échouer (et lever une exception) si le formatage demandé n'a pas de sens.
Par exemple, si le type à formater n'est pas compatible avec le formater, ici une chaîne à formater en octal :
Ou si la syntaxe du formater est incorrecte ou incohérente :
Cette erreur arrive lors de l’exécution.
De son coté, PyF fait ses vérifications lors de la phase de vérification des types, avant l’exécution.
Ici j'ai exécuté les exemples dans l’interpréteur Haskell, mais je vous demande de me croire que l'erreur est bien une erreur "statique" détectée pendant la compilation et non lors de l’exécution.
De plus, les erreurs de PyF apportent plus de contexte (notez le petit marqueur
^
qui montre précisément la localisation du problème.) Ce ne fut pas une tache aisée, et c'est loin d'être parfait, mais cela permet tout de même de voir l'erreur pendant la phase de développement et non lors de l’exécution.D'ailleurs, pour rentrer dans les détails, PyF peut échouer dans 2 contextes différents.
No instance for (Integral [Char])
qui veut simplement dire qu'une chaîne de caractère n'est pas convertible en nombre entier. Il y aurait moyen d'améliorer cela un petit peu, il faut que j'y passe un peu de temps, mais il est possible en Haskell de contrôler les message d'erreur des erreurs de type.Bref, au final, PyF apporte, comparé à Python, une partie de vérification "statique" lors de la compilation. C'est à mon avis appréciable, après tout, c'est ce que j’apprécie en Haskell, mais ce n'est pas l'apport le plus intéressant qui reste la partie formatage, et là, PyF n'apporte rien de mieux que ce que python propose en standard.
# Trop c'est trop !
Posté par fmapx . Évalué à 4.
Merci pour le temps passé qu'il a dû falloir pour rédiger cette dépêche.
Pour le reste, ce que je regrette avec Haskell c'est qu'il est plus long et compliqué d'assimiler les multiples extensions de GHC plutôt que le langage en lui-même qui est plutôt agréable.
Ce que je veux dire c'est que c'est pas très rassurant pour industrialiser le dev.
Suivre le flux des commentaires
Note : les commentaires appartiennent à celles et ceux qui les ont postés. Nous n’en sommes pas responsables.