Je ne comprends tout simplement pas quel problème ils résolvent.
haskell
pragmatism
monad
Emploi
la source
la source
Réponses:
Les monades ne sont ni bonnes ni mauvaises. Ils le sont. Ce sont des outils qui sont utilisés pour résoudre des problèmes comme de nombreuses autres constructions de langages de programmation. Une application très importante d'entre eux est de faciliter la vie des programmeurs travaillant dans un langage purement fonctionnel. Mais ils sont utiles dans les langages non fonctionnels; c'est juste que les gens réalisent rarement qu'ils utilisent une Monade.
Qu'est-ce qu'une monade? La meilleure façon de penser à une monade est un modèle de conception. Dans le cas des E / S, vous pourriez probablement le considérer comme étant un peu plus qu'un pipeline glorifié où l'état global est ce qui se passe entre les étapes.
Par exemple, prenons le code que vous écrivez:
Il se passe beaucoup plus de choses ici qu'il n'y paraît. Par exemple, vous remarquerez que
putStrLn
a la signature suivante:putStrLn :: String -> IO ()
. Pourquoi est-ce?Pensez-y de cette façon: supposons (par souci de simplicité) que stdout et stdin sont les seuls fichiers que nous pouvons lire et écrire. Dans un langage impératif, ce n'est pas un problème. Mais dans un langage fonctionnel, vous ne pouvez pas muter l'état global. Une fonction est simplement quelque chose qui prend une valeur (ou des valeurs) et renvoie une valeur (ou des valeurs). Une façon de contourner cela consiste à utiliser l'état global comme valeur qui est transmise à chaque fonction. Vous pouvez donc traduire la première ligne de code en quelque chose comme ceci:
... et le compilateur saurait imprimer tout ce qui est ajouté au deuxième élément de
global_state
. Maintenant, je ne sais pas pour vous, mais je détesterais programmer comme ça. La façon dont cela a été rendu plus facile était d'utiliser les Monades. Dans une Monade, vous passez une valeur qui représente une sorte d'état d'une action à l'autre. C'est pourquoiputStrLn
a un type de retour deIO ()
: il renvoie le nouvel état global.Alors, pourquoi vous en souciez-vous? Eh bien, les avantages de la programmation fonctionnelle par rapport au programme impératif ont été débattus à plusieurs reprises, donc je ne vais pas répondre à cette question en général (mais consultez cet article si vous voulez entendre le cas de la programmation fonctionnelle). Pour ce cas spécifique, il pourrait être utile de comprendre ce que Haskell essaie d'accomplir.
Beaucoup de programmeurs pensent que Haskell essaie de les empêcher d'écrire du code impératif ou d'utiliser des effets secondaires. Ce n'est pas tout à fait vrai. Pensez-y de cette façon: un langage impératif est celui qui autorise les effets secondaires par défaut, mais vous permet d'écrire du code fonctionnel si vous le souhaitez vraiment (et êtes prêt à faire face à certaines des contorsions qui nécessiteraient). Haskell est purement fonctionnel par défaut, mais vous permet d'écrire du code impératif si vous le souhaitez vraiment (ce que vous faites si votre programme est utile). Le but n'est pas de rendre difficile l'écriture de code qui a des effets secondaires. C'est pour vous assurer que vous êtes explicite sur les effets secondaires (avec le système de type qui applique cela).
la source
goto
(comme argument pour une programmation structurée) un peu plus loin dans le document, qualifiant ces arguments de "infructueux". Et pourtant, aucun de nous ne souhaite secrètementgoto
le retour. C'est simplement que vous ne pouvez pas dire que cegoto
n'est pas nécessaire pour les personnes qui l'utilisent intensivement.Je vais mordre !!! Les monades en elles-mêmes ne sont pas vraiment une raison d'être pour Haskell (les premières versions de Haskell n'en avaient même pas).
Votre question est un peu comme dire "C ++ quand je regarde la syntaxe, je m'ennuie tellement. Mais les modèles sont une fonctionnalité très annoncée de C ++ donc j'ai regardé une implémentation dans un autre langage".
L'évolution d'un programmeur Haskell est une blague, elle n'est pas destinée à être prise au sérieux.
Une Monade aux fins d'un programme dans Haskell est une instance de la classe de type Monade, c'est-à-dire qu'il s'agit d'un type qui prend en charge un certain petit ensemble d'opérations. Haskell a un support spécial pour les types qui implémentent la classe de type Monad, en particulier le support syntaxique. En pratique, il en résulte ce que l'on a appelé un «point-virgule programmable». Lorsque vous combinez cette fonctionnalité avec certaines des autres fonctionnalités de Haskell (fonctions de première classe, paresse par défaut), vous obtenez la possibilité d'implémenter certaines choses en tant que bibliothèques qui étaient traditionnellement considérées comme des fonctionnalités de langage. Vous pouvez par exemple implémenter un mécanisme d'exception. Vous pouvez implémenter la prise en charge des continuations et des coroutines en tant que bibliothèque. Haskell, le langage ne prend pas en charge les variables mutables:
Vous demandez "Peut-être / Identité / Monades de division sûre ???". La monade Maybe est un exemple de la façon dont vous pouvez implémenter (très simple, une seule exception) la gestion des exceptions en tant que bibliothèque.
Vous avez raison, écrire des messages et lire les entrées des utilisateurs n'est pas très unique. IO est un exemple moche de «monades en tant que fonctionnalité».
Mais pour itérer, une "fonctionnalité" en elle-même (par exemple Monades) isolée du reste du langage ne semble pas nécessairement immédiatement utile (une grande nouvelle fonctionnalité de C ++ 0x est les références rvalue, ne signifie pas que vous pouvez prendre les sortir du contexte C ++ car sa syntaxe vous ennuie et voit forcément l'utilitaire). Un langage de programmation n'est pas quelque chose que vous obtenez en lançant un tas de fonctionnalités dans un compartiment.
la source
Les programmeurs écrivent tous des programmes, mais les similitudes s'arrêtent là. Je pense que les programmeurs diffèrent beaucoup plus que la plupart des programmeurs ne peuvent l'imaginer. Prenez n'importe quelle «bataille» de longue date, comme le typage de variables statiques vs les types d'exécution uniquement, les scripts vs compilés, le style C vs orienté objet. Il vous sera impossible d'argumenter rationnellement qu'un camp est inférieur, car certains d'entre eux génèrent un excellent code dans un système de programmation qui me semble inutile ou même carrément inutilisable.
Je pense que différentes personnes pensent simplement différemment, et si vous n'êtes pas tenté par le sucre syntaxique ou en particulier les abstractions qui n'existent que pour des raisons de commodité et qui ont en fait un coût d'exécution important, alors restez loin de ces langues.
Je recommanderais cependant que vous essayiez au moins de vous familiariser avec les concepts que vous abandonnez. Je n'ai rien contre quelqu'un qui est résolument pro-pur-C, tant qu'il comprend réellement le gros problème des expressions lambda. Je soupçonne que la plupart ne deviendront pas immédiatement un fan, mais au moins ce sera là à l'arrière de leur esprit quand ils trouveront le problème parfait, ce qui aurait été tellement plus facile à résoudre avec les lambdas.
Et, surtout, essayez d'éviter de vous ennuyer en parlant de fanboy, surtout par des gens qui ne savent pas de quoi ils parlent.
la source
Haskell applique la transparence référentielle : étant donné les mêmes paramètres, chaque fonction renvoie toujours le même résultat, quel que soit le nombre de fois que vous appelez cette fonction.
Cela signifie, par exemple, que sur Haskell (et sans Monades), vous ne pouvez pas implémenter un générateur de nombres aléatoires. En C ++ ou Java, vous pouvez le faire en utilisant des variables globales, en stockant la valeur "seed" intermédiaire du générateur aléatoire.
Sur Haskell, l'équivalent des variables globales sont les Monades.
la source
Random
objet.C'est une vieille question, mais elle est vraiment bonne, alors je vais répondre.
Vous pouvez considérer les monades comme des blocs de code pour lesquels vous avez un contrôle total sur la façon dont ils sont exécutés: ce que chaque ligne de code doit retourner, si l'exécution doit s'arrêter à tout moment, si un autre traitement doit avoir lieu entre chaque ligne.
Je vais donner quelques exemples de choses que les monades permettent et qui seraient difficiles autrement. Aucun de ces exemples n'est en Haskell, juste parce que mes connaissances en Haskell sont un peu chancelantes, mais ce sont tous des exemples de la façon dont Haskell a inspiré l'utilisation des monades.
Analyseurs
Normalement, si vous vouliez écrire un analyseur quelconque, par exemple pour implémenter un langage de programmation, vous devriez soit lire la spécification BNF et écrire tout un tas de code en boucle pour l'analyser, soit utiliser un compilateur compilateur comme Flex, Bison, yacc etc .. Mais avec les monades, vous pouvez faire une sorte de "compilateur analyseur" directement dans Haskell.
Les analyseurs ne peuvent pas vraiment se faire sans monades ni langages spéciaux comme le yacc, le bison, etc.
Par exemple, j'ai pris la spécification du langage BNF pour le protocole IRC :
Et je l'ai réduit à environ 40 lignes de code en F # (qui est un autre langage qui prend en charge les monades):
La syntaxe monade de F # est assez moche par rapport à celle de Haskell, et j'aurais probablement pu améliorer cela un peu - mais le point à retenir est que structurellement, le code de l'analyseur est identique au BNF. Non seulement cela aurait pris beaucoup plus de travail sans monades (ou générateur de parseurs), mais cela n'aurait eu presque aucune ressemblance avec les spécifications, et aurait donc été terrible à lire et à maintenir.
Multitâche personnalisé
Normalement, le multitâche est considéré comme une fonctionnalité du système d'exploitation - mais avec les monades, vous pouvez écrire votre propre planificateur de telle sorte qu'après chaque monade d'instructions, le programme passe le contrôle au planificateur, qui choisit ensuite une autre monade à exécuter.
Un gars a créé une monade "tâche" pour contrôler les boucles de jeu (encore une fois en F #), de sorte qu'au lieu d'avoir à tout écrire comme une machine d'état qui agit à chaque
Update()
appel, il pourrait simplement écrire toutes les instructions comme s'il s'agissait d'une seule fonction .En d'autres termes, au lieu d'avoir à faire quelque chose comme:
Vous pourriez faire quelque chose comme:
LINQ to SQL
LINQ to SQL est en fait un exemple de monade, et des fonctionnalités similaires pourraient facilement être implémentées dans Haskell.
Je n'entrerai pas dans les détails car je ne me souviens pas de tout cela avec précision, mais Erik Meijer l'explique assez bien .
la source
Si vous connaissez les modèles GoF, les monades sont comme le modèle Decorator et le modèle Builder réunis, sur des stéroïdes, mordus par un blaireau radioactif.
Il y a de meilleures réponses ci-dessus, mais certains des avantages spécifiques que je vois sont:
les monades décorent un type de noyau avec des propriétés supplémentaires sans changer le type de noyau. Par exemple, une monade peut "soulever" une chaîne et ajouter des valeurs comme "isWellFormed", "isProfanity" ou "isPalindrome" etc.
de même, les monades permettent de conglomérer un type simple en un type de collection
les monades permettent la liaison tardive des fonctions dans cet espace d'ordre supérieur
les monades permettent de mélanger des fonctions et des arguments arbitraires avec un type de données arbitraire, dans l'espace d'ordre supérieur
les monades permettent de mélanger des fonctions pures et sans état avec une base impure et avec état, de sorte que vous pouvez garder une trace de l'endroit où le problème est
Un exemple familier d'une monade en Java est List. Il prend une classe de base, comme String, et la "lève" dans l'espace monade de List, ajoutant des informations sur la liste. Ensuite, il lie de nouvelles fonctions dans cet espace comme get (), getFirst (), add (), empty (), etc.
À grande échelle, imaginez qu'au lieu d'écrire un programme, vous venez d'écrire un gros Builder (comme le modèle GoF), et la méthode build () à la fin crache la réponse que le programme était censé produire. Et que vous pourriez ajouter de nouvelles méthodes à votre ProgramBuilder sans recompiler le code d'origine. C'est pourquoi les monades sont un modèle de conception puissant.
la source