J'ai vraiment hate de voir ce que cela va apporter en terme de performance, support matériel (GPU en particulier). J'aimerais vraiment avoir un pipeline de build / dépendance unifié entre linux et windows.
Par robuste, j'entendais le fait que en parsant des fichier .h, si le format des fichiers .h change pour une raison absurde (nouvelle norme de C par example), le parseur sera à revoir.
Alors que, de ce que j'ai compris, l'introspection de gobject s'occupe de fournir les scanners et le format de sortie normalisé.
Ma question était plutôt sur l’intérêt de réinventer la roue sachant que la force de GTK (à mon avis) c'est ce coté hyper "bindable" grâce à son architecture d'introspection.
Un programme Python se charge de parcourir les fichiers .h des bibliothèques GTK afin d’essayer d’en extraire la substantifique moelle à l’aide d’expressions régulières et de générer les interfaces Fortran permettant d’accéder aux fonctions C.
La force de gtk ce n'est pas justement de fournir des outils d'introspection permettant de générer des bindings facilement et sans passer par des expressions régulières peu robustes ?
λ paddle ~ → python
The program ‘python’ is currently not installed...
λ paddle ~ → nix-shell -p 'python3.withPackages(p : [])'
[nix-shell:~]$ python
Python 3.7.2 (default, Dec 24 2018, 03:41:55)
[GCC 7.4.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import numpy
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ModuleNotFoundError: No module named 'numpy'
>>>
KeyboardInterrupt
>>>
[nix-shell:~]$ ^C
[nix-shell:~]$ exit
λ paddle ~ → nix-shell -p 'python3.withPackages(p : [p.numpy])'
[nix-shell:~]$ python
Python 3.7.2 (default, Dec 24 2018, 03:41:55)
[GCC 7.4.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import numpy
>>>
KeyboardInterrupt
>>>
[nix-shell:~]$ ^C
[nix-shell:~]$ exit
λ paddle ~ → nix-shell -p 'python2.withPackages(p : [p.numpy])'
these derivations will be built:
/nix/store/4r2lhzcnblj58pbalpw6s0j0q34mrdc3-python-2.7.15-env.drv
building '/nix/store/4r2lhzcnblj58pbalpw6s0j0q34mrdc3-python-2.7.15-env.drv'...
created 686 symlinks in user environment
[nix-shell:~]$ python
Python 2.7.15 (default, Apr 29 2018, 23:18:59)
[GCC 7.4.0] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import numpy
>>>
KeyboardInterrupt
>>>
GtkListStore permet aussi de stocker un object abstrait (i.e. un pointeur). J'e m'étais servi de cela il y a très longtemps (en 2007) pour implémenter l'interface d'une base de donnée de club de bande dessiné.
L'idée étant que mon GtkListStore ne contenant que des objets python (j'utilisais pygtk) et c'était les views qui s'occupaient de récupérer le contenu des columns. C'était très pratique.
Merci pour ce journal qui fait une bonne synthèse du problème.
Dans mes souvenir un pauvre hello world en C++ se retrouve tout de suite avec des tonnes d'includes en cascade, dont beaucoup ne sont des bibliothèques standards fournies par le compilo (donc ne devant jamais changer en théorie…).
Ce qui est bien avec "en théorie" c'est que cela ne marche jamais ;)
Pour faire un vrai build reproductible à 100%, tu ne peux pas supposer que tes dépendances système ne changent pas. Et aussi, tu ne veux pas utiliser les dépendances système, car tu n'as pas de contrôle dessus, mais ceci est une autre histoire. En bref, tu veux absolument faire ce traitement de vérification.
Je serais intéressé par des benchmarks, mais le coût de l'appel système pour construire la liste de dépendance est très faible comparé au coût du build. Et une fois que le build est fait, tu as un cache du graph de dépendance, la seule chose qui devient nécessaire c'est de vérifier que tes dépendances sont à jour.
L'approche est intéressante et déja utilisée dans de nombreux autre outils:
Le problème de cette approche c'est que tu ne connais le graph de dépendance qu'une fois que tu a réalisé un build complet, ce qui est acceptable sur un petit projet, mais pas sur un gros, car en pratique on build rarement un projet en entier. Par example, ici, je travaille sur une sous partie d'un projet logiciel dont le build ne prend que 2h sur mon gros i7. Mais l'ensemble du projet prend plusieurs jours.
Note que ce n'est pas une critique fondamentale de l'outil, c'est un problème seulement si tu as un gros projet pour lequel tu veux faire un build partiel.
Rhaaa ;) Merci. Si un modérateur voulait bien se donner la peine (dernier paragraphe). J'en profite pour remercier les relectures et contributeurs qui ont su jongler avec mon orthographe déplorable ;)
Pour ma part je ne suis absolument pas du tout du web / application mobile, alors le jour ou j'ai du en réaliser une, j'ai cherché comment faire en Haskell ;)
J'ai utilisé Reflex et, une fois le setup de reflex-plateform effectué, c'est très agréable. Ce qui est vraiment fort c'est de pouvoir develloper sur son ordinateur en testant dans son navigateur, avec un rebuild instantané, et d'avoir l'application mobile qui sort automatiquement après.
La façon de programmer de Reflex (i.e. le "Reactive programming") est très agréable à utiliser quand je compare au plat de nouille que j'aurais pu faire si je l'avais fais en mode evénement / callback. Ceci est à prendre avec des pincettes, car ce n'est pas du tout mon domaine de prédilection.
Les plus de Reflex, de mon point de vu limité :
Reactive programming, le tout très bien intégré à Haskell. Un Event est une instance de Functor, donc map fonctionne dessus.
Ecrire un widget réutilisable est un bonheur.
Accès à tout l'écosystème Haskell et à (presque) toutes les librairies.
Le code frontend et backend (si besoin) peu être partagé. Ma première version de l'application avait un backend en Haskell (depuis j'utilise google drive), et c'était très agréable de manipuler des deux cotés les mêmes types, surtout pour les requêtes à l'API.
De façon amusante, Reflex s'en sort très bien avec les librairies qui modifient ton DOM en même temps tant que les choses restent cohérentes.
Les moins:
Il n'y a pas de MVC ou autre. C'est à toi d'architecturer proprement.
Reflex.Dom c'est du web, donc il faut à minima y comprendre quelque chose en mise en page avec des CSS. Il y a quelques libraries (comme Clay: http://fvisser.nl/clay/) qui permettent d'éditer facilement du CSS, mais je me suis vraiment perdu dans ces histoire de flex ou table ou autre. Une personne habituée au CSS n'aura pas ce problème. On doit aussi pouvoir utiliser des librairies de layout toute prêtes, mais je n'y connais rien.
Le FFI avec javascript. Soit t'as un binding déjà fait pour faire ce que tu veux faire, soit c'est l'horreur. Par example, Reflex.Dom n'avait rien (à l'époque) pour accéder aux webstorage, j'ai du le faire à la main.
Pas de template Haskell si tu veux compiler pour mobile. Ce n'est pas dramatique, mais c'est agaçant. Et bien evidament toutes les librairies Haskell qui ont une dépendance à une sous librairie écrite en C ne passeront pas si tu veux compiler pour javascript.
Le javascript generé est gros et lent. Ce n'est pas un problème si tu vises une machine de bureau, mais c'est un problème pour mobile. Heureusement tu peux compiler en natif pour mobile (ios et android), donc ce n'est pas une grosse limitation.
Rien n'est fait pour utiliser le code natif en mode mobile, ce sera donc à toi de le faire si tu veux par example utiliser l'API fichier de ton Android.
Et si les deux étaient intéressant ? Imaginons que la vitesse d’exécution soit une contrainte fonctionnelle critique de ton produit. On peut imaginer préférer un produit faux (i.e.: avec des bugs, des plantages, des imprécisions) mais extrêmement rapide que l'inverse.
Techniquement les commandes nix communiquent avec le "store" par le biais d'un daemon. Le demon est le seul à pouvoir écrire dans la store. Il est par contre tout à fait possible de lui faire écrire ce que l'on veut mais sans pouvoir écraser un autre répertoire. Par contre il est vrai que tu peux mettre un truc dangereux dans le store et demander à un utilisateur de l'exécuter. Mais c'est la même chose que lui demander d'exécuter un ficher reçu par mail…
Pour moi les deux sont totalement indépendant. Docker ne gere pas les programmes / librairies installées. Il n'y a rien de choquant d'avoir un nix dans NixOS (ou n'importe quelle autre distrib) dans un docker.
Par contre, pour le dev tous les jours, nix est suffisant pour ne pas avoir besoin de docker.
Petite remarque, il faut faire nix-env -u --always pour mettre à jour tout. Sinon par défaut il ne met pas à jour les paquets qui ne changent pas de numéro de version.
En fait l'installation est partagée entre chaque utilisateur ET nix gère la déduplication entre fichiers du store. C'est pratique si par exemple tu as plusieurs version d'un même programme.
-Wconversion te donnera un warning adapté. Je recommande cette option, malheureusement sur une base de code existante elle génère tellement de warning que c'est des heures de travail pour la fixer.
A titre d’exemple, c'est mon fil rouge depuis 5 ans dans ma boite. Quand j'ai quelques minutes de libre, j'en fixe une dizaine.
Notons que visual studio est plus strict par défaut à ce niveau.
le code brainfuck ne comprend que le calcul du tempo puisque d'après le fichier TapTempoBF.hs les chaînes de caractère de début et de fin ne sont pas dans le programme proprement dit ?
Si, le fichier TapTempoBF.hs ne fait que "générer" le code brainfuck. À vrai dire l'affichage de caractères statiques est ce qu'il y a de plus simple en brainfuck ;)
Ce que fait réellement le code brainfuck :
Affichage des chaines
"Stimulation" du registre matériel pour avoir le temps
Lecture du delta de temps, division pour avoir le rythme en bpm, affichage.
Gestion des entrées, de la boucle, de quitter avec 'q'
Le seul truc spéciale que fait la VM brainfuck c'est le registre hardware pour le temps (là je ne vois pas d'autre solution) et il calcul le delta de temps tout seul. J'aurais clairement pu juste mettre le temps actuel dans un registre et faire la soustraction en brainfuck, mais les soustraction de grandes valeurs prennent un temps linéaire, ce qui aurait été catastrophique.
Très bonne question ! Il faut bien comprendre que le compilateur GHC n'a AUCUNE notion de type raffinés. Pour lui, un Integer reste un Integer, i.e. un entier de taille infinie.
La librairie refined propose simplement un type Refined qui, de manière simpliste, peut être vue comme un objet ne contenant qu'un seul membre privé de type Integer. Comme il n'y a pas de conversion implicite en Haskell, un Integer (comme 5) ne peut pas être vu comme un Refined, il faut le convertir.
On ne peut pas obtenir d'erreur à l’exécution : soit on utilise refineTH lors de la compilation (et l'erreur sera le cas échéant à la compilation), soit on utilise refine à l’exécution et on est forcé de tester le résultat de la conversion.
Ce type Refined est très limité, il n'accepte pas d'autres opérations (comme l'addition, la soustraction, …) Ainsi il ne peut être vraiment pratique que pour des valeurs constante. On peut imaginer trois exemples de fonction division :
Celle qui ne gère pas l'erreur et qui va planter à l’exécution :
myDiv::Integer->Integer->IntegermyDivab=divab
Celle qui gère l'erreur et renvoie une valeur représentant la réussite ou l'échec, ce qui force l'appelant de la fonction à gérer le cas sur le résultat:
myDiv::Integer->Integer->MaybeIntegermyDiv_0=NothingmyDivab=Just(divab)-- plus tardcasemyDivabofJustres->putStrLn("C'est bon: "++showres)Nothing->putStrLn"Erreur"
L'approche qui ne peut pas échouer, mais force l'appelant à fournir le bon type "raffiné" :
myDiv::Integer->Refined(Or(LessThan0)(GreaterThan0))Integer->IntegermyDivab=divab-- plus tardcaserefinebofLefterreur->putStrLn"Erreur"JustbRefined->putStrLn("C'est bon"++show(myDivabRefined))
Dans ce dernier cas que je préfère, le type de la fonction est bien plus informatif, et le code de la fonction est plus simple. Et si tu possède déjà un type raffiné, tu peux t'affranchir des tests et ainsi il n'y a pas de coût à l’exécution :
Qui n'aura pas plus de coût à l’exécution que l'appel à la fonction div.
On pourrait cependant imaginer une libraire d'un peu plus haut niveau capable d'opérations arithmétiques entre les types. C'est le cas par exemple de Liquid Haskell qui est un analyseur statique de code Haskell. Par exemple, il peut prouver que div x (abs x + 1) est correct car :
quelque que soit x, abs x >= 0
abs x + 1 >= 1
div x (abs x + 1) est défini (car point précédant) et différent de 0.
Cet exemple est assez simple et on pourrait facilement réaliser un type Haskell qui permet ces opérations. Cependant des cas plus complexes ne sont pas possible à exprimer dans le système de type et demandent donc un outil externe, comme Liquid Haskell.
[^] # Re: Maieuh !
Posté par Guillaum (site web personnel) . En réponse au journal Windows est enfin prêt pour le desktop . Évalué à 4.
J'ai vraiment hate de voir ce que cela va apporter en terme de performance, support matériel (GPU en particulier). J'aimerais vraiment avoir un pipeline de build / dépendance unifié entre linux et windows.
# Nixos
Posté par Guillaum (site web personnel) . En réponse au journal Shebang #!/usr/bin/env sh : testé et approuvé. Évalué à 6.
J'allais te dire nixos, mais en fait non ;)
[^] # Re: gobject introspection
Posté par Guillaum (site web personnel) . En réponse à la dépêche Sortie de gtk-fortran 19.04. Évalué à 4.
Par robuste, j'entendais le fait que en parsant des fichier .h, si le format des fichiers .h change pour une raison absurde (nouvelle norme de C par example), le parseur sera à revoir.
Alors que, de ce que j'ai compris, l'introspection de gobject s'occupe de fournir les scanners et le format de sortie normalisé.
Ma question était plutôt sur l’intérêt de réinventer la roue sachant que la force de GTK (à mon avis) c'est ce coté hyper "bindable" grâce à son architecture d'introspection.
# gobject introspection
Posté par Guillaum (site web personnel) . En réponse à la dépêche Sortie de gtk-fortran 19.04. Évalué à 6.
La force de gtk ce n'est pas justement de fournir des outils d'introspection permettant de générer des bindings facilement et sans passer par des expressions régulières peu robustes ?
[^] # Re: Xkcd
Posté par Guillaum (site web personnel) . En réponse au journal Quelques bonnes pratiques Python pour 2019. Évalué à 3.
Et nix fait déjà ça et gère les packets python.
# GtkListStore et object
Posté par Guillaum (site web personnel) . En réponse au journal Utilisation de GtkTreeModel, GtkTreeView et consorts. Évalué à 4.
GtkListStore permet aussi de stocker un object abstrait (i.e. un pointeur). J'e m'étais servi de cela il y a très longtemps (en 2007) pour implémenter l'interface d'une base de donnée de club de bande dessiné.
L'idée étant que mon GtkListStore ne contenant que des objets python (j'utilisais pygtk) et c'était les views qui s'occupaient de récupérer le contenu des columns. C'était très pratique.
Merci pour ce journal qui fait une bonne synthèse du problème.
[^] # Re: OMG !!!
Posté par Guillaum (site web personnel) . En réponse au journal une formation à être parent. Évalué à 5.
Et un couple qui marche bien c'est un couple qui n'oublie pas la notion d'individu.
[^] # Re: Quid des perfs ?
Posté par Guillaum (site web personnel) . En réponse au journal `smk`, un make sans Makefile. Évalué à 6.
Ce qui est bien avec "en théorie" c'est que cela ne marche jamais ;)
Pour faire un vrai build reproductible à 100%, tu ne peux pas supposer que tes dépendances système ne changent pas. Et aussi, tu ne veux pas utiliser les dépendances système, car tu n'as pas de contrôle dessus, mais ceci est une autre histoire. En bref, tu veux absolument faire ce traitement de vérification.
Je serais intéressé par des benchmarks, mais le coût de l'appel système pour construire la liste de dépendance est très faible comparé au coût du build. Et une fois que le build est fait, tu as un cache du graph de dépendance, la seule chose qui devient nécessaire c'est de vérifier que tes dépendances sont à jour.
L'approche est intéressante et déja utilisée dans de nombreux autre outils:
Le problème de cette approche c'est que tu ne connais le graph de dépendance qu'une fois que tu a réalisé un build complet, ce qui est acceptable sur un petit projet, mais pas sur un gros, car en pratique on build rarement un projet en entier. Par example, ici, je travaille sur une sous partie d'un projet logiciel dont le build ne prend que 2h sur mon gros i7. Mais l'ensemble du projet prend plusieurs jours.
Note que ce n'est pas une critique fondamentale de l'outil, c'est un problème seulement si tu as un gros projet pour lequel tu veux faire un build partiel.
[^] # Re: Vérifier si deux énoncés parmi N (N >= 2) sont vrais, en Python
Posté par Guillaum (site web personnel) . En réponse au journal Carnet de route - taume 0. Évalué à 2.
Non, pas que je sache.
accumulate
,map
etany
sontO(n)
dans le pire des cas.# Vérifier si deux énoncés parmi N (N >= 2) sont vrais, en Python
Posté par Guillaum (site web personnel) . En réponse au journal Carnet de route - taume 0. Évalué à 7.
Si tu veux vraiment faire dans le oneliner, et que tu veux un early exit, que penser de :
Cela demande l'import de
itertools
, mais aucun développeur qui se respecte ne travaillerait sans importer celui-ci.[^] # Re: Et si on faisait une petite dépêche sur Idris?
Posté par Guillaum (site web personnel) . En réponse à la dépêche GHC 8.4 et 8.6. Évalué à 2.
Avec grand plaisir. Même si ton seul argument pour idris c'est le strict par défaut, c'est dommage ;)
Idris est un super langage, mon seul regret c'est que c'est assez dur de trouver du boulot avec, alors que Haskell c'est plutôt trivial.
[^] # Re: Coquille
Posté par Guillaum (site web personnel) . En réponse à la dépêche GHC 8.4 et 8.6. Évalué à 3.
Rhaaa ;) Merci. Si un modérateur voulait bien se donner la peine (dernier paragraphe). J'en profite pour remercier les relectures et contributeurs qui ont su jongler avec mon orthographe déplorable ;)
[^] # Re: Article sympa a lire
Posté par Guillaum (site web personnel) . En réponse à la dépêche Développement Web frontend en Haskell, Elm et Purescript. Évalué à 7.
Hello,
Pour ma part je ne suis absolument pas du tout du web / application mobile, alors le jour ou j'ai du en réaliser une, j'ai cherché comment faire en Haskell ;)
J'ai fais ça pour ma femme: https://github.com/guibou/givorsDays
J'ai utilisé Reflex et, une fois le setup de reflex-plateform effectué, c'est très agréable. Ce qui est vraiment fort c'est de pouvoir develloper sur son ordinateur en testant dans son navigateur, avec un rebuild instantané, et d'avoir l'application mobile qui sort automatiquement après.
La façon de programmer de Reflex (i.e. le "Reactive programming") est très agréable à utiliser quand je compare au plat de nouille que j'aurais pu faire si je l'avais fais en mode evénement / callback. Ceci est à prendre avec des pincettes, car ce n'est pas du tout mon domaine de prédilection.
Les plus de
Reflex
, de mon point de vu limité :Event
est une instance deFunctor
, doncmap
fonctionne dessus.Les moins:
Reflex.Dom
c'est du web, donc il faut à minima y comprendre quelque chose en mise en page avec des CSS. Il y a quelques libraries (comme Clay: http://fvisser.nl/clay/) qui permettent d'éditer facilement du CSS, mais je me suis vraiment perdu dans ces histoire deflex
outable
ou autre. Une personne habituée au CSS n'aura pas ce problème. On doit aussi pouvoir utiliser des librairies de layout toute prêtes, mais je n'y connais rien.[^] # Re: Paquet ArchLinux/Manjaro
Posté par Guillaum (site web personnel) . En réponse à la dépêche GIMP 2.10 roule au GEGL. Évalué à 4.
Gimp est maintenant dans
nixpkgs-unstable
, donc:[^] # Re: Paquet ArchLinux/Manjaro
Posté par Guillaum (site web personnel) . En réponse à la dépêche GIMP 2.10 roule au GEGL. Évalué à 4.
En une seule commande:
Qui dit mieux ?
[^] # Re: la vitesse d'exécution n'est pas le principal intérêt d'un compilateur à mes yeux.
Posté par Guillaum (site web personnel) . En réponse au journal Pythran 0.8.5 - de l'intérêt des compilateurs. Évalué à 3.
Et si les deux étaient intéressant ? Imaginons que la vitesse d’exécution soit une contrainte fonctionnelle critique de ton produit. On peut imaginer préférer un produit faux (i.e.: avec des bugs, des plantages, des imprécisions) mais extrêmement rapide que l'inverse.
[^] # Re: Et par utilisateur
Posté par Guillaum (site web personnel) . En réponse à la dépêche Le gestionnaire de paquets Nix en version 2.0. Évalué à 3.
Techniquement les commandes nix communiquent avec le "store" par le biais d'un daemon. Le demon est le seul à pouvoir écrire dans la store. Il est par contre tout à fait possible de lui faire écrire ce que l'on veut mais sans pouvoir écraser un autre répertoire. Par contre il est vrai que tu peux mettre un truc dangereux dans le store et demander à un utilisateur de l'exécuter. Mais c'est la même chose que lui demander d'exécuter un ficher reçu par mail…
[^] # Re: voir aussi… GNU Guix
Posté par Guillaum (site web personnel) . En réponse à la dépêche Le gestionnaire de paquets Nix en version 2.0. Évalué à 3.
Pour moi les deux sont totalement indépendant. Docker ne gere pas les programmes / librairies installées. Il n'y a rien de choquant d'avoir un nix dans NixOS (ou n'importe quelle autre distrib) dans un docker.
Par contre, pour le dev tous les jours, nix est suffisant pour ne pas avoir besoin de docker.
[^] # Re: Quid des mises à jour de sécurité ?
Posté par Guillaum (site web personnel) . En réponse à la dépêche Le gestionnaire de paquets Nix en version 2.0. Évalué à 5.
Petite remarque, il faut faire
nix-env -u --always
pour mettre à jour tout. Sinon par défaut il ne met pas à jour les paquets qui ne changent pas de numéro de version.[^] # Re: Et par utilisateur
Posté par Guillaum (site web personnel) . En réponse à la dépêche Le gestionnaire de paquets Nix en version 2.0. Évalué à 3.
En fait l'installation est partagée entre chaque utilisateur ET nix gère la déduplication entre fichiers du store. C'est pratique si par exemple tu as plusieurs version d'un même programme.
[^] # Re: Commande nix
Posté par Guillaum (site web personnel) . En réponse à la dépêche Le gestionnaire de paquets Nix en version 2.0. Évalué à 3.
nix-shell
etnix-env
n'existent pas encore dans les nouvelles commandes.[^] # Re: Namespace bits ?
Posté par Guillaum (site web personnel) . En réponse au journal Jouons avec le ``switch`` et C++17. Évalué à 2.
Par contre je suis étonné que clang ne soit pas capable de mélanger les morceaux de code identiques:
C'est stressant quand à l'impact sur les performances que les templates peuvent avoir (duplication d'assembleur -> trash du cache d'instruction)
[^] # Re: Intérêt de refineTH ?
Posté par Guillaum (site web personnel) . En réponse au journal Portage de TapTempo en Haskell. Évalué à 4.
-Wconversion
te donnera un warning adapté. Je recommande cette option, malheureusement sur une base de code existante elle génère tellement de warning que c'est des heures de travail pour la fixer.A titre d’exemple, c'est mon fil rouge depuis 5 ans dans ma boite. Quand j'ai quelques minutes de libre, j'en fixe une dizaine.
Notons que visual studio est plus strict par défaut à ce niveau.
[^] # Re: Excellent
Posté par Guillaum (site web personnel) . En réponse au journal TapTempo en brainfuck. Évalué à 5.
Si, le fichier TapTempoBF.hs ne fait que "générer" le code brainfuck. À vrai dire l'affichage de caractères statiques est ce qu'il y a de plus simple en brainfuck ;)
Ce que fait réellement le code brainfuck :
Le seul truc spéciale que fait la VM brainfuck c'est le registre hardware pour le temps (là je ne vois pas d'autre solution) et il calcul le delta de temps tout seul. J'aurais clairement pu juste mettre le temps actuel dans un registre et faire la soustraction en brainfuck, mais les soustraction de grandes valeurs prennent un temps linéaire, ce qui aurait été catastrophique.
[^] # Re: Intérêt de refineTH ?
Posté par Guillaum (site web personnel) . En réponse au journal Portage de TapTempo en Haskell. Évalué à 4.
Très bonne question ! Il faut bien comprendre que le compilateur GHC n'a AUCUNE notion de type raffinés. Pour lui, un
Integer
reste unInteger
, i.e. un entier de taille infinie.La librairie refined propose simplement un type
Refined
qui, de manière simpliste, peut être vue comme un objet ne contenant qu'un seul membre privé de typeInteger
. Comme il n'y a pas de conversion implicite en Haskell, unInteger
(comme5
) ne peut pas être vu comme unRefined
, il faut le convertir.On ne peut pas obtenir d'erreur à l’exécution : soit on utilise
refineTH
lors de la compilation (et l'erreur sera le cas échéant à la compilation), soit on utiliserefine
à l’exécution et on est forcé de tester le résultat de la conversion.Ce type
Refined
est très limité, il n'accepte pas d'autres opérations (comme l'addition, la soustraction, …) Ainsi il ne peut être vraiment pratique que pour des valeurs constante. On peut imaginer trois exemples de fonction division :Dans ce dernier cas que je préfère, le type de la fonction est bien plus informatif, et le code de la fonction est plus simple. Et si tu possède déjà un type raffiné, tu peux t'affranchir des tests et ainsi il n'y a pas de coût à l’exécution :
Qui n'aura pas plus de coût à l’exécution que l'appel à la fonction
div
.On pourrait cependant imaginer une libraire d'un peu plus haut niveau capable d'opérations arithmétiques entre les types. C'est le cas par exemple de Liquid Haskell qui est un analyseur statique de code Haskell. Par exemple, il peut prouver que
div x (abs x + 1)
est correct car :x
,abs x >= 0
abs x + 1 >= 1
div x (abs x + 1)
est défini (car point précédant) et différent de 0.Cet exemple est assez simple et on pourrait facilement réaliser un type Haskell qui permet ces opérations. Cependant des cas plus complexes ne sont pas possible à exprimer dans le système de type et demandent donc un outil externe, comme Liquid Haskell.