Je pense que c'est un peu l'opinion. Mais je vais tenter de répondre.
Je suis d'accord avec Dietrich Ppe: c'est une combinaison de plusieurs choses qui font de GHC rapide.
D'abord et avant tout, Haskell est de très haut niveau. Cela permet au compilateur d'effectuer des optimisations agressives sans casser votre code.
Pensez-SQL. Maintenant, quand j'écris un SELECT
relevé, cela peut ressembler à un impératif de la boucle, mais il n'est pas. Il pourrait ressembler , il passe en boucle sur toutes les lignes de la table en essayant de trouver celui qui correspond aux conditions spécifiées, mais en fait le "compilateur" (le moteur DB) pourrait être en train de faire une recherche d'index au lieu — qui a complètement différentes caractéristiques de performance. Mais parce que SQL est donc de haut niveau, le "compilateur" peut se substituer totalement différents algorithmes, appliquer plusieurs processeurs ou de canaux d'e/S ou d'un ensemble de serveurs de manière transparente, et plus encore.
Je pense que de Haskell comme étant le même. Vous pourriez penser que vous venez de lui demander Haskell à la carte la liste d'entrée pour une deuxième liste, filtre de la deuxième liste dans une troisième liste, puis de compter le nombre d'éléments qui en a résulté. Mais vous n'avez pas voir GHC appliquer stream-fusion des règles de réécriture dans les coulisses, transformant le tout en une seule serré du code machine de la boucle qui fait tout le travail en une seule passe sur les données avec aucune allocation — le genre de chose qui serait fastidieux, source d'erreurs et de non-maintenable d'écrire à la main. C'est vraiment possible en raison de l'absence de détails de bas niveau dans le code.
Une autre façon de voir les choses peut-être... pourquoi ne pas Haskell être rapide? Qu'est-ce cela qui doit être lent?
Ce n'est pas un langage interprété comme Perl ou JavaScript. Il n'est même pas un système de la machine virtuelle comme le Java ou le C#. Il compile tout le chemin vers du code machine natif, donc pas de frais généraux.
Contrairement aux langages à objets [Java, C#, JavaScript...], Haskell a plein de type d'effacement [comme en C, C++, Pascal...]. Tous type de vérification qui se passe au moment de la compilation. Donc il n'y a aucun moment de l'exécution de la vérification de type à vous ralentir. (Pas de pointeur null vérifie, pour cette question. Dans, par exemple, Java, la JVM doit vérifier les pointeurs nuls et de lever une exception si vous déférence. Haskell n'a pas à s'embêter avec cette case.)
Vous dites que c'sons lents à "créer des fonctions à la volée au moment de l'exécution", mais si vous regardez attentivement, vous, vous n'avez pas réellement le faire. Il pourrait ressembler à vous le faites, mais vous n'avez pas. Si vous dites (+5)
, eh bien, c'est codé en dur dans votre code source. Il ne peut pas changer au moment de l'exécution. Il n'est donc pas vraiment une fonction dynamique. Même des fonctions curryfiées sont vraiment juste sauvegarde des paramètres dans un bloc de données. Tous les code exécutable existe réellement au moment de la compilation; il n'est pas au moment de l'exécution de l'interprétation. (Contrairement à certains autres langues qui ont une "fonction eval".)
Penser à Pascal. Il est vieux et que personne ne l'utilise plus, mais personne ne s'en plaindrait que Pascal est lente. Il y a beaucoup de choses à détester à ce sujet, mais la lenteur n'est pas vraiment un d'entre eux. Haskell n'est pas vraiment faire grand chose de différent de Pascal, que la collecte des ordures plutôt que manuel de gestion de la mémoire. Et immuables de données permet à plusieurs optimisations pour le moteur GC [qui lazy evaluation ensuite complique un peu].
Je pense que le truc, c'est que Haskell semble avancées et sophistiquées et de haut niveau, et tout le monde pense "oh wow, c'est vraiment puissant, il doit être incroyablement lent!" Mais il n'est pas. Ou au moins, elle n'est pas dans la façon dont vous le souhaitez. Oui, il a un incroyable système de type. Mais vous savez quoi? Tout ce qui se passe au moment de la compilation. Par moment, il a disparu. Oui, il permet de construire compliqué ADTs avec une ligne de code. Mais vous savez quoi? L'ADT est juste un ordinaire C union
de struct
s. Rien de plus.
Le véritable assassin est paresseux évaluation. Lorsque vous obtenez la rigueur / paresse de votre code droit, vous pouvez écrire bêtement rapide code qui est toujours belle et élégante. Mais si vous obtenez ce genre de choses de mal, votre programme va des milliers de fois plus lent, et il est vraiment non-évident pourquoi ce qui se passe.
Par exemple, j'ai écrit un banal petit programme pour compter combien de fois chaque octet apparaît dans un fichier. Pour un 25 KO fichier d'entrée, le programme a pris 20 minutes pour exécuter et d'ingestion 6 gigaoctets de RAM! C'est absurde!! Mais ensuite j'ai réalisé que le problème a été, ajouté un seul bang-du motif et de la durée d'utilisation est tombé à 0.02 secondes.
C' est là que Haskell va lentement de façon inattendue. Et c'est sûr qu'il faut un certain temps pour s'y habituer. Mais au fil du temps, il devient plus facile d'écrire vraiment rapide du code.
Ce qui fait Haskell si vite? La pureté. Types statiques. La paresse. Mais par-dessus tout, être suffisamment haut niveau que le compilateur peut changer radicalement la mise en œuvre sans casser votre code attentes.
Mais je suppose que c'est juste mon avis...