Pourquoi est-il bon de ne pas compter sur un changement d'état?


16

Cette question découle de la question /software/25569/is-haskell-worth-learning

Généralement, quelques déclarations souvent répétées sont faites sur la façon dont Haskell améliore vos compétences de codage dans d'autres langues, et en outre, c'est parce que Haskell est apatride, et c'est une bonne chose.

Pourquoi?

J'ai vu quelqu'un comparer cela à seulement taper avec la main gauche, ou peut-être fermer les yeux pendant une journée et s'appuyer simplement sur le toucher. Il y a sûrement plus que cela?

Est-ce lié à l'accès à la mémoire matérielle ou à quelque chose d'autre qui est un gros gain de performances?


2
Haskell est universitaire. Je regarderais quelques conférences de Rich Hickey sur Clojure - là, il fait des arguments pragmatiques de tueur (similaire aux 3 points de Javier, mais aussi fait de manière simple).
Job


6
Ce n'est pas parce que Haskell est "académique" qu'il n'est pas pratique ou pas pragmatique.
Tikhon Jelvis

Réponses:


17

il y a au moins trois gros avantages du haut de ma tête:

  1. cela rend les programmes plus proches des expressions mathématiques. En mathématiques, xcela ne change pas, vous ne savez pas ce que c'est tant que vous n'avez pas résolu l'équation.

  2. En fin de compte, il y a un changement d'état (après tout, c'est comme ça que l'ordinateur fonctionne à bas niveau); mais il est limité par la langue à des endroits spécifiques. cela permet au compilateur d’énormes possibilités de déplacer le code pour l’optimiser, car il sait qu’il ne change rien à ce dont dépend un autre code.

  3. Le code simultané n'a pas besoin de se synchroniser pour accéder aux données inchangées, donc la concurrence est améliorée, à la fois dans les systèmes de mémoire partagée SMP (tous les systèmes multicœurs d'aujourd'hui) et sur les clusters faiblement liés.


3
Les propositions de programmation fonctionnelle mettent le plus de stress # 3, c'est-à-dire une simplification de la concurrence simultanée.
Mchl

4
@Mchl: D'après mon expérience, ils ont mis l'accent sur "C'est plus facile à comprendre et à raisonner", ce qui correspond à 1. Bien que je suppose que cela pourrait différer entre les communautés linguistiques.
sepp2k du

+1, réponse très complète. @ sepp2k: les deux sont importants, je suppose. Raisonner sur un programme est ce que nous faisons quotidiennement, et il est vrai que si vous n'avez pas à vérifier que l'état n'a pas changé dans une fonction profondément cachée, il est beaucoup plus facile de lire uniquement les méthodes de haut niveau et de voir ce qui se passe. Côté matériel: étant donné que nous nous dirigeons de plus en plus vers les multicœurs et les multi-processeurs (même si je suppose que cela prendra un certain temps avant que les ordinateurs personnels ne deviennent multi-processeurs), avoir un langage qui facilite la programmation simultanée est une prime.
Matthieu M.

Bonne réponse, # 2 était ce que je présumais être la réponse, et bien que j'aie lu souvent sur les avantages du multitraitement, c'est rarement dit aussi clairement, excellent travail.
ocodo

1
@Yttrill, les langages fonctionnels ne sont pas uniques dans leur dépendance à la collecte des ordures et la collecte des ordures est beaucoup plus facile lorsque vous traitez avec des données immuables. Faire n'importe quel calcul sur une architecture basée sur des instructions signifie modifier l'état, cela ne signifie pas que les langages fonctionnels sont en quelque sorte plus difficiles à paralléliser. Les langages fonctionnels basculent au parallélisme; recherche de données parallèle à Haskell, c'est une fonctionnalité qu'il serait presque impossible d'ajouter à un langage impératif.
dan_waterworth

4

Voici un autre avantage: couplage réduit. Si vous avez du code comme:

 function doStuff(x) { return x + y;}

et ailleurs vous avez:

 function doOtherStuff(x) { y++; return y + x;}

alors les deux fonctions dépendent implicitement . Il n'y a aucun moyen facile de dire que l'appel doStuffest affecté par l'appel doOtherStuff. Sans état mutable, vous devez rendre la connexion explicite.

Bien sûr, ce n'est pas un problème avec tous les états mutables - le problème est avec un état mutable omniprésent. La vraie solution est d'avoir l'immuabilité par défaut et un moyen de "marquer" et de contraindre l'état mutable là où vous en avez besoin.


+1. De nombreux programmeurs expérimentés ne savent pas écrire du code comme ci-dessus et ce n'est pas une étape énorme pour passer de "l'état mutable est mauvais dans cette situation" à "réduisons sérieusement la quantité d'état que nous mutons et écrivons plus fonctionnellement", mais c'est une étape que peu de gens font.
dan_waterworth

2

Une réponse simplifiée est la suivante: lorsque vous voyez un nom dans un langage purement fonctionnel, vous savez quelle est la valeur associée par une simple recherche de sa définition. Si vous avez des variables mutables, vous ne pouvez dire que par laquelle des nombreuses affectations qui lui ont été exécutées en dernier, vous devez donc également analyser le flux de contrôle, qui à son tour peut être conditionnel, vous laissant plusieurs possibilités. Pour obtenir une explosion exponentielle, il vous suffit de considérer que les RHS des affectations dépendent elles-mêmes de variables, vous devez donc les analyser de manière récursive également.

L'essentiel de l'analyse ci-dessus est qu'elle est intenable sans commentaires expliquant l'intention, les invariants et la sémantique: ceux-ci peuvent être difficiles à interpréter, et il peut être difficile de vérifier que la sémantique est respectée dans le code réel.

Cette réponse est essentiellement une extension du point 1 de @ Javier.

Je pense que c'est également une explication de la popularité du régime OO frauduleux: avec OO, l'état mutable est encapsulé, ce qui facilite beaucoup l'analyse en localisant les mutations dans une certaine mesure et en permettant une expression et une vérification beaucoup plus robustes de la sémantique.

Cela dit, la programmation fonctionnelle n'est pas la réponse. La bonne réponse est un système qui prend en charge la programmation inductive (fonctionnelle) et coinductive (procédurale), de sorte que les bons outils peuvent gérer à la fois la programmation sans état et avec état. C'est juste que la théorie constructive (fonctionnelle) est bien établie alors que la théorie de la gestion de l'État en est encore à ses balbutiements.


Mélanger la programmation fonctionnelle et impérative est exactement ce que fait Haskell - les fonctions normales sont fonctionnelles tandis que les calculs avec état peuvent être exprimés avec une notation do qui vous permet d'isoler et de contrôler soigneusement l'état mutable (entre autres). C'est pourquoi le langage avec l'implémentation STM la plus pratique est Haskell .
Tikhon Jelvis

Do-notation n'a pas vraiment rien à faire le calcul stateful en soi . La Do-notation n'est qu'une syntaxe plus simple au-dessus des pipelines de fonctions monadiques. Le calcul avec état n'est qu'une des choses qui peuvent être exprimées en utilisant des monades, et donc la do-notation.
Jonathan Sterling

La programmation mixte fonctionnelle et impérative est ce que font presque tous les langages existants. Haskell a peut-être fourni un moyen d'isoler les parties avec état, mais cela n'en fait pas un mélange approprié: la charité ressemble plus à ce qu'elle devrait être (à mon humble avis).
Yttrill

2

En tant qu'auteur de Siege , un SGBD écrit en Haskell, certains peuvent appeler mon avis sur l'état mutable en conflit. J'espère montrer le contraire.

Le but de l'état mutable est de décrire l'état actuel dans lequel se trouve un système. Supposons que vous ayez un blog et qu'il soit géré par une base de données, la base de données décrit les publications que vous avez sur votre blog au moment où vous interrogez il. Combien de messages existent actuellement?

Comparez cela à l'état immuable qui est utilisé pour transmettre des faits. Combien de postes y avait-il le 12 août?

Les faits sont faciles à raisonner, l'état mutable ne l'est pas. Cependant, l'état mutable n'est pas un effet impur maléfique qui devrait être banni de la portée de nos esprits; nous en avons souvent besoin pour coexister dans le monde mutable dans lequel nous vivons, nous devons simplement l'utiliser avec plus de parcimonie.

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.