|
Publicité ' | ||||||||||||||||||||||||
|
|
#1 |
|
Nouveau Membre du Club
![]() Inscription : juin 2009 Messages : 86 ![]() |
Haskell est un langage excellent, bien pensé et qui a de grande qualités, mais rien n'est parfait si on essaie d'avoir un regard critique, et je pense qu'il est bien de voir tous les aspects.
Du coup, si vous aviez des choses (petites ou grosses) à lui reprocher, ça serait quoi ? Pour ma part, ça tient du détail, mais je pense qu'un système de namespaces aurait été le bienvenu. On peut s'en rapprocher avec les imports qualifiés, mais c'est moins flexible. |
|
|
00
|
|
|
#2 | |
|
Expert Confirmé Sénior
![]() ![]() |
Citation:
Pour ce qui est des reproches à adresser à Haskell... J'aimerais un système de type plus puissant ! On peut faire des choses très impressionnante avec l'actuel mais je suis convaincu qu'on peut faire encore mieux sans perdre en flexibilité. J'aimerais également un meilleur moyen de combiner les monades que les transformateurs de monades. Et il serait pratique de pouvoir traduire automatiquement du code vers une écriture monadique. J'ai d'autres reproches qui ne me reviennent pas sur l'instant. -- Jedaï |
|
|
|
00
|
|
|
#3 | |||
|
Nouveau Membre du Club
![]() Inscription : juin 2009 Messages : 86 ![]() |
Citation:
Le souci quand on développe un code Haskell est qu'on se retrouve très rapidement avec beaucoup de fonctions, certaines ayant souvent des noms très proches (cf. certaines fonctions, genre de Data.Map, qui ont le même nom que des fonctions du Prelude) et que j'aurais aimé un moyen en plus des imports qualifiés pour répartir et retrouver mes fonctions. Avec seulement les imports qualifiés, les problèmes sont les suivants : - Pas moyen de définir un nom d'import standard pour un module. Ex: Je peux importer Data.Map en tant que M, mais quelqu'un d'autre pourra l'importer en tant que Map ou DM ou n'importe quoi d'autre. Ca n'aide pas pour s'y retrouver quand au sein d'un même projet on a plusieurs fois le même module, mais importé sous des noms différents. Avec un namespace Map, tout le monde serait logé à la même enseigne. - Il faut indiquer à chaque fois les alias, alors qu'avec un namespace ce serait automatique. Citation:
Citation:
|
|||
|
|
00
|
|
|
#4 | ||||
|
Expert Confirmé Sénior
![]() ![]() |
Citation:
Code Haskell :
Ce que "as" t'apporte de plus c'est la possibilité de définir un alias. Citation:
Plutôt du ressort de la refactorisation à mon avis. -- Jedaï |
||||
|
|
00
|
|
|
#5 | |||
|
Nouveau Membre du Club
![]() Inscription : juin 2009 Messages : 86 ![]() |
Citation:
|
|||
|
|
00
|
|
|
#6 |
|
Membre éprouvé
![]() |
Haskell est dur a apprendre. En tout cas pour quelqu'un comme moi qui ne connait que l'objet et le procédural.
|
|
|
00
|
|
|
#7 |
|
Nouveau Membre du Club
![]() Inscription : juin 2009 Messages : 86 ![]() |
Explique-toi.
Si Haskell est dur à apprendre parce qu'il fonctionne d'une manière très différente de ce que tu connais, ça ne peut pas être une critique. Si Haskell fonctionnait pareil que les langages mainstream, il aurait beaucoup moins d'intérêt. Il est intéressant avant justement tout parce qu'il propose un modo operandum et une logique différents. Si maintenant tu trouves qu'Haskell est dur à apprendre parce qu'il te semble que ses créateurs ne font pas d'effort pour aider les débutants (qui en d'autant plus besoin du fait de sa logique différente), ça c'est autre autre chose. Effectivement, les messages d'erreur de GHC sont assez opaques pour le newbie. |
|
|
00
|
|
|
#8 |
|
Membre éprouvé
![]() |
Ben tu demandes si on a un reproche a faire a Haskell, moi j'en ai un.
Après si il est impossible de corriger cette imperfection sans dénaturer totalement le langage, alors il faut trouver une autre réponse (le faire enseigner dans les université, écoles, par exemple). |
|
|
00
|
|
|
#9 | |
|
Membre du Club
![]() ![]() Maxime Gaudin Inscription : novembre 2005 Messages : 17 ![]() |
Citation:
|
|
|
00
|
|
|
#10 |
|
Membre Expert
![]() Inscription : avril 2007 Messages : 829 ![]() |
- le compilateur GHC est trop compliqué, lourd, et long à compiler
- rentre GHCi agréable à utiliser pour coder de petits exemples (quand on est habitué au toplevel OCaml, il y a un monde) - si on pouvait reconcevoir haskell aujourd'hui, j'essaierais d'enlever la paresse par défaut (par exemple, en ajoutant des spécifications d'appel sur les types des fonctions, où on choisit entre un traitement lazy ou strict de chaque paramètre, le défaut étant le strict) - essayer de concevoir un meilleur support pour les ambiguités de type classes : je veux pouvoir donner plusieurs structures de monoïde à l'ensemble des entiers naturels, sans devoir changer de type; cela passe sans doute par une réification de certains dictionnaires - ajouter un mot-clé "rec" ou un équivalent pour préciser les valeurs récursives; dans le cas par défaut, les noms déclarés ne seraient pas dans la portée de leur déclaration - un langage de contraintes plus puissant et plus composable (il y a un article à ce sujet : Haskell Type Constraints Unleashed) - arrêter de traiter la monade IO comme un gros blurb où on peut tout mettre (entrée-sortie, concurrence..) - des outils pour rendre plus facile la programmation au niveau des types, comme par exemple une couche de langage logique spécialisée, ou la définition d'un sous-ensemble de Haskell où aucune valeur ne diverge, pour pouvoir l'utiliser dans les types (mais sans forcément autoriser les types dépendants dans toute leur généralité, pour préserver la distinction typage/exécution) Edit : un petit point auquel j'avais déjà pensé, que j'ai oublié de mentionner, mais que je viens de retrouver très bien exprimé dans un post de Tim Sweeney : pas de différence entre la syntaxe (ou la sémantique) des déclarations toplevel et des déclarations locales. |
|
|
00
|
|
|
#11 |
|
Membre du Club
![]() Inscription : janvier 2010 Messages : 46 ![]() |
Tu pourrais préciser ? Personnellement je préfère largement GHCi ne serait-ce que pour l'autocomplétion et la mémorisation des expressions entrées.
|
|
|
00
|
|
|
#12 |
|
Membre Expert
![]() Inscription : avril 2007 Messages : 829 ![]() |
Le fait que la syntaxe des déclarations dans GHCi et dans le Haskell classique soient très différentes est assez pénalisant. En pratique je n'arrive jamais à entrer des programmes de plus d'une ligne dans GHCi.
En gros, il est impossible d'utiliser GHCi pour coder, même de petites choses : tout ce que j'arrive à lui demander, c'est le type ou la valeur d'expressions venant d'un programme externe. C'est pratique, mais ça limite sérieusement l'utilité d'un interpréteur interactif (par rapport par exemple à un éditeur qui donne des informations de typage si on lui demande gentiment). Ce sont des problèmes de surface, moins importants que d'autres (mais en même temps la syntaxe toplevel des déclarations Haskell doit contribuer à la difficulté de faire une REPL pratique à utiliser; mais on pourrait ajouter un opérateur pour dire "c'est la fin d'un bloc de déclarations", un peu comme le ';;' OCaml). |
|
|
00
|
|
|
#13 |
|
Membre Expert
![]() Inscription : mars 2007 Messages : 852 ![]() |
Je serais intéressé de savoir en quoi c'est important. Pour moi, cela permet d'éliminer un mot-clé, et le seul désavantage que je vois est qu'on ne peut pas référencer une ancienne valeur liée à cet identifiant, ce qui me semble un mauvais style de toute façon (cela peut donner l'impression que la valeur est récursive si on ne fait pas assez attention).
|
|
|
00
|
|
|
#14 | |||||||||
|
Membre Expert
![]() Inscription : avril 2007 Messages : 829 ![]() |
Citation:
L'intérêt de pouvoir accéder aux anciennes valeurs n'est en fait pas tellement le fait d'y accéder, mais surtout le fait de pouvoir les cacher. Dans un certain nombre de contextes, on a envie de mettre à jour une valeur, et on veut s'assurer que toutes les références suivantes se feront sur la nouvelle. Le cas typique est du style "let x = secure x in ..." : on veut cacher la définition de la valeur x, en la remplaçant par une valeur "sécurisée", et faire référence ensuite à la version sécurisée. En haskell on utilise des "... where x' = secure x", mais le risque est alors de se tromper et d'écrire x au lieu de x'. Si les deux valeurs ne sont pas du même type, le compilateur détecte l'erreur, mais ce n'est pas toujours le cas. Exemples trouvés dans du vrai code, par Google Code Search : Code :
Code :
Code :
Il vaut mieux réserver ce style aux cas où justement, on a besoin de l'ancienne référence (ce sont en général des cas assez subtils où il faut faire bien attention, donc il est important de mettre l'accent sur l'utilisation à un endroit de x ou de x'), et cacher dans le reste des cas le binding, ce qui enlève un poids mental sur le programmeur en réduisant le nombre d'identifiants actifs, et le risque d'erreur. Il n'y a pas de risque de confondre cela avec une définition récursive, puisque les récursions seraient explicitement marquées par "rec". Il suffit de vérifier la présence ou non de "rec" pour savoir si une définition est récursive, et de toute façon tous les exemples que j'ai montrés sont évidemment non-récursifs (à part les petits malins qui s'amusent à faire du "Tying back the knot", personne de sain d'esprit n'écrirait "x = secure x" si c'était récursif). On a déjà discuté de ça par ici, et certains Haskelliens ont répondu, et je pense qu'ils n'ont pas forcément tort, que Haskell favorise le style récursif car il s'allie bien avec la paresse par défaut (l'idée plus ou moins vraie que tout ce qu'on définit est un cofixpoint). Dans ce cas, on pourrait imaginer un mot clé "nonrec" à mettre dans l'autre sens, pour permettre tout de même les idiomes que j'ai montrés. Je pense cependant que le style récursif est celui qu'il convient de marquer explicitement (même en Haskell la récursion n'est pas si courante, surtout avec l'emploi lourds de combinateurs tels que fold/map/etc.), surtout si on le combine avec mon idée d'explorer des possibilités de ne pas avoir la paresse par défaut. Enfin, il y a des situations en métaprogrammation où on a envie de générer des programmes en surveillant la portée des identifiants, pour empêcher certaines choses. Il est facile d'utiliser des déclarations locales pour éviter qu'un identifiant ne se propage en dehors d'un bloc, mais la syntaxe Haskell actuelle empêche de cacher un identifiant dans sa portée lexicale, ce qui peut être un problème. Par exemple, dans le papier "Comprehensive Comprehensions" (Wadler and Peyton Jones, 07), qui propose une syntaxe de list comprehension en Haskell avec des fonctionnalités empruntées de SQL, on trouve la proposition suivante pour GROUP BY : Code :
Si on imagine qu'on traduit cette syntaxe vers du code Haskell standard, la redéfinition peut poser problème : il est possible que la nouvelle déclaration des variables comme liste utilise l'ancienne déclaration des variables comme éléments (surtout si les variables utilisées dans le code généré ne représentent pas les variables elles-même, mais une description abstraite des variables, comme on doit faire si on espère par exemple générer une requête SQL à la fin (ce qui n'est pas le cas dans l'article)). La syntaxe Haskell de haskell pose alors problème, et il faut faire des acrobaties diverses pour éviter les captures/récursions. |
|||||||||
|
|
00
|
|
|
#15 | |
![]() ![]() Damien GuichardInscription : juin 2007 Messages : 1 514 ![]() |
Citation:
J'ajouterais un seul reproche :
Mais si j'avais à faire la liste des reproches à OCaml elle serait au moins aussi longue (pauvreté des types entiers de base, boxed floats, code mort dans les modules, pas de région-based memory-management,...,...).
__________________
Du même auteur: le cours OCaml, le dernier article publié, le projet, le blog dvp et le jeu vidéo. Avant de poser une question je lis les règles du forum. |
|
|
00
|
|
|
#16 |
|
Membre Expert
![]() Inscription : avril 2007 Messages : 829 ![]() |
Je suis d'accord sur l'exhaustivité des filtrages, mais je pense qu'il faudrait une construction syntaxique pour la désactiver localement (car parfois on a envie de dire que seul un cas est possible).
Pour les reproches à OCaml, je t'invite à créer un topic à ce sujet, ce serait certainement intéressant. D'ailleurs, j'ai du rater quelque chose car je ne comprends pas pourquoi tu reproches à Caml l'absence de régions, alors qu'à ma connaissance Haskell n'en a pas. Est-ce que Haskell en a déjà, ou tu penses que ce ne serait pas utile/pertinent dans ce langage ? |
|
|
00
|
|
|
#17 | |
![]() ![]() Damien GuichardInscription : juin 2007 Messages : 1 514 ![]() |
Je pense que tous les langages devraient avoir le region-based memory-management.
À commencer par le D et autres prétendants à la succession du C. Citation:
__________________
Du même auteur: le cours OCaml, le dernier article publié, le projet, le blog dvp et le jeu vidéo. Avant de poser une question je lis les règles du forum. |
|
|
00
|
|
|
#18 | |||
|
Expert Confirmé Sénior
![]() ![]() |
GHC permet déjà de vérifier l'exhaustivité des filtrages avec -fwarn-incomplete-patterns (ou -Wall), il y a aussi l'outil Catch qui est censé être capable dans certains cas de vérifier que des patterns partiels traitent correctement tous les cas possibles.
@bluestorm : Citation:
Citation:
Reste que GHCi ne permet pas de déclarer des nouveaux types ou instances, il serait intéressant de rendre cela possible (il n'y a pas a priori d'obstables techniques réels). Citation:
Je suis d'accord avec le reste de tes remarques. -- Jedaï |
|||
|
|
00
|
|
|
#19 |
|
Nouveau Membre du Club
![]() Inscription : juin 2009 Messages : 86 ![]() |
Je pourrais aussi reprocher un léger manque de consistance au niveau de certains opérateurs (notamment la '->' qui est allègrement utilisée partout).
Par exemple, une fonction se déclare ainsi: f x = 3*x Pourquoi une fonction lambda n'est-elle pas déclarée ainsi: \x = 3*x au lieu de \x -> 3*x ? |
|
|
00
|
|
|
#20 |
|
Membre Expert
![]() Inscription : avril 2007 Messages : 829 ![]() |
Parce que la première ligne est une égalité (f, appliqué à x, égale 3 x), alors que dans la deuxième il n'y a rien d'égal : "\x = 3*x" suggèrerait au mieux que x = 3*x, donc une forme de récursion. Il s'agit ici d'une fonction : à x on associe 3x. Le "->" est d'ailleurs bien le même "->" que dans un motif ("case .. of") par exemple : si on reconnaît le motif "x", on renvoie "3*x".
|
|
|
00
|
Copyright © 2000-2013 - www.developpez.com