Comprendre les monades

C’est quoi ? À quoi ça sert ?

Le problème exposé dans ce sujet a été résolu.

Il existe de très nombreuses façons d’aborder les monades, en témoignent les 85 articles sur le sujet que je donne en lien dans la conclusion. Nécessairement, certaines plaisent plus aux uns ou aux autres. Pour ma part, je trouve justement qu’on manque de cours utilisant une approche « pragmatique », c’est-à-dire ne faisant pas appel à des concepts mathématiques, aussi basiques (en apparence, du moins) soient-ils.

Je comprends tout à fait l’approche par la généralisation du concept de composition de fonctions, et d’ailleurs, je l’évoque en passant dans la dernière section. Mais de mon expérience, le fait même de généraliser un concept abstrait est un obstacle à la compréhension de beaucoup de gens : sans cela, on n’aurait aucun mal à faire comprendre les groupes ou les espaces vectoriels…

D’où mon approche.

En fait, la plupart des abstractions fournies par un langage peuvent se réencoder dans un autre langage (les types algébriques, les pointeurs), seulement cela ne veut pas dire que c'est intéressant de le faire.

Je ne suis que moyennement d’accord avec cette affirmation. Faire de la POO en Haskell, ce n’est pas possible, et le C++ se prête très mal à simuler des types algébriques de données (et je parle pas de Python…). Du coup, le fait qu’il soit possible de créer une monade dans un langage impératif est relativement significatif.

Maintenant, je n’ai pas forcément assez insisté sur le fait que c’est effectivement un outil peu adapté au paradigme, je vais corriger ce point-là.

Du coup je me demande quelles sont des motivations pour la partie "Un outils multi-language" ? En quoi cela permet au lecteur de mieux comprendre la monade (la question peut s'adresser aussi aux lecteurs) ?

La quasi-totalité des tutos sur les monades parlent uniquement de Haskell. C’est compréhensible, c’est clairement le langage le plus adapté pour en parler. Le but de cette section, c’est de montrer que Haskell est loin d’être le seul langage où les monades peuvent être un outil adapté. D’où quelques exemples de monades qui marchent bien… et quelques exemples de monades qui ne marchent pas. ^^

Un exemple un peu plus concret à mon avis, et qui permet de vraiment comprendre l'intérêt des monades dans des cas d'utilisations conrets c'est de faire un interpréteur pour un langage hyper réduit.

C’est typiquement le genre de choses que je veux éviter. ;) Faire un interpréteur pour un langage créé pour l’occasion, à mes yeux, ça tient plus de la branlette intellectuelle que d’un bon exemple d’utilisation concrète. Alors qu’un calcul simple dans lequel se glisse un résultat impossible, tout le monde comprend.

Il y a aussi l’exemple de la recherche dans une base de données généalogique, où les fonction père et mère peuvent échouer à chaque génération. C’est sur ça que j’étais parti au départ, mais ça demandait un code beaucoup plus encombré pour que les exemples fonctionnent sans intervention extérieure, donc j’ai laissé tomber.

Le dernier point que je souhaite soulevé c'est les monades en théorie des catégories. Pour avoir suivi un cours de catégorie en M2, c'est une notion assez compliquée et dont l'intérêt est loin d'être évident. C'est bien de savoir que la notion originale vient des catégories, mais pour le moment c'est inutile d'aller plus loin. D'autant plus qu'un tutoriel parlant des monades en catégorie aurait besoin de beaucoup trop de prérequis.

Saroupille

C’est aussi mon point de vue, d’où le fait que je n’en parle pas dans mon cours. Je laisse à quelqu’un d’autre le soin de le faire. :)

+0 -0

Je comprends tout à fait l’approche par la généralisation du concept de composition de fonctions, et d’ailleurs, je l’évoque en passant dans la dernière section. Mais de mon expérience, le fait même de généraliser un concept abstrait est un obstacle à la compréhension de beaucoup de gens : sans cela, on n’aurait aucun mal à faire comprendre les groupes ou les espaces vectoriels…

D’où mon approche.

On est d'accord. Juste je voulais insister sur le fait qu'il n'y a pas qu'une explication possible et que dans ce cas là c'est dommage d'attendre la toute fin du tutoriel pour mentionner les autres explications (d'ailleurs ça m'avait échappé au premier regard).

En fait, la plupart des abstractions fournies par un langage peuvent se réencoder dans un autre langage (les types algébriques, les pointeurs), seulement cela ne veut pas dire que c'est intéressant de le faire.

Je ne suis que moyennement d’accord avec cette affirmation. Faire de la POO en Haskell, ce n’est pas possible,

Apparemment, il y a des gens qui ont essayé pour la POO en Haskell (je n'ai pas lu l'article) : http://arxiv.org/pdf/cs/0509027v1.pdf

Et de façon plus général, il est apparemment possible de réencoder des principes de POO en Haskell.

et le C++ se prête très mal à simuler des types algébriques de données (et je parle pas de Python…). Du coup, le fait qu’il soit possible de créer une monade dans un langage impératif est relativement significatif.

Qu'entends-tu par significatif ? Comment interprètes-tu alors le fait qu'on puisse encoder les typages algébriques en C++ ? Est-ce aussi significatif ?

La quasi-totalité des tutos sur les monades parlent uniquement de Haskell. C’est compréhensible, c’est clairement le langage le plus adapté pour en parler. Le but de cette section, c’est de montrer que Haskell est loin d’être le seul langage où les monades peuvent être un outil adapté. D’où quelques exemples de monades qui marchent bien… et quelques exemples de monades qui ne marchent pas. ^^

J'ai pas compris ce qui marchait, mais dès que j'ai le temps j'irai relire cette partie.

Un exemple un peu plus concret à mon avis, et qui permet de vraiment comprendre l'intérêt des monades dans des cas d'utilisations conrets c'est de faire un interpréteur pour un langage hyper réduit.

C’est typiquement le genre de choses que je veux éviter. ;) Faire un interpréteur pour un langage créé pour l’occasion, à mes yeux, ça tient plus de la branlette intellectuelle que d’un bon exemple d’utilisation concrète. Alors qu’un calcul simple dans lequel se glisse un résultat impossible, tout le monde comprend.

J'ai un peu du mal à comprendre ton point de vue sur ça. Je trouve qu'au contraire un interpréteur est un exemple concret et loin d'être de la branlette intellectuelle. D'une part, car avec un tout petit langage, on peut faire quelque chose de Turing-Complet, et en plus on va pouvoir revisiter les idiomes fonctionnels (types algébriques, pattern-matching, fonction récursives, …). Un tel exemple permet donc de voir comment les monades peuvent se combiner avec ces idiomes.

Enfin, même si on ne va pas développer un interpréteur tous les jours, les principes fonctionnels qui mènent à développer un interpréteur efficace (non pertinents pour ce tutoriel) donnent une bonne illustration de la puissance de ce paradigme (CPS pour la récursivité terminale par exemple).

Ce que je reprochais à l'exemple que tu donnais, c'est qu'il est minimal.

Source:Dominus Carnufex

On est d'accord. Juste je voulais insister sur le fait qu'il n'y a pas qu'une explication possible et que dans ce cas là c'est dommage d'attendre la toute fin du tutoriel pour mentionner les autres explications (d'ailleurs ça m'avait échappé au premier regard).

Ça n’aurait pas trop de sens de dire « Si mon explication ne vous plaît pas, en voici d’autres. » avant ladite explication. ;)

Qu'entends-tu par significatif ? Comment interprètes-tu alors le fait qu'on puisse encoder les typages algébriques en C++ ? Est-ce aussi significatif ?

Significatif quant au fait que les monades ne sont pas un joujou réservé au Haskell. Et quant aux ADT, ce n’est pas le sujet du cours, donc très sincèrement, on s’en tape. :)

J'ai pas compris ce qui marchait, mais dès que j'ai le temps j'irai relire cette partie.

Les deux premiers exemples, en OCaml et en Rust.

J'ai un peu du mal à comprendre ton point de vue sur ça. Je trouve qu'au contraire un interpréteur est un exemple concret et loin d'être de la branlette intellectuelle. D'une part, car avec un tout petit langage, on peut faire quelque chose de Turing-Complet, et en plus on va pouvoir revisiter les idiomes fonctionnels (types algébriques, pattern-matching, fonction récursives, …). Un tel exemple permet donc de voir comment les monades peuvent se combiner avec ces idiomes.

Enfin, même si on ne va pas développer un interpréteur tous les jours, les principes fonctionnels qui mènent à développer un interpréteur efficace (non pertinents pour ce tutoriel) donnent une bonne illustration de la puissance de ce paradigme (CPS pour la récursivité terminale par exemple).

Ce que je reprochais à l'exemple que tu donnais, c'est qu'il est minimal.

Tu sembles oublier les objectifs de ce cours : faire comprendre l’abstraction, et rien de plus. La connaissance demandée en programmation fonctionnelle est minimale, j’explique la syntaxe de tous les exemples, et je laisse de côté ce qui n’est pas entièrement nécessaire à la compréhension (par exemple, la définition de la classe de types Monad ou les lois des monades). Dans ces conditions, un exemple qui mette en jeu de nombreux idiomes de programmation fonctionnelle, qui pis est dans 4 ou 5 langages différents, serait parfaitement hors de propos.

+0 -0

Ça n’aurait pas trop de sens de dire « Si mon explication ne vous plaît pas, en voici d’autres. » avant ladite explication. ;)

Ce n'est pas ce que je dis. Je dis qu'il existe d'autres façon de voir les monades. Certaines sont plus mathématiques (généralisation des fonctions, catégories, …), d'autres plus pragmatique (une interface). Bref, ce que je dis c'est qu'il ne serait pas illogique de voir des références externes au milieu du tutoriel en introduisant la référence. C'est d'ailleurs ce qui est fait en général.

Significatif quant au fait que les monades ne sont pas un joujou réservé au Haskell. Et quant aux ADT, ce n’est pas le sujet du cours, donc très sincèrement, on s’en tape. :)

Ok mais mes questions étaient liées au paragraphe précédent. Je ne comprend pas comment tu détermines qu'une abstraction d'un certains langage ré encodée dans un autre langage va être utile ou non. Tu dis que ce n'est pas le cas pour ADT, mais que ça l'ait pour les monades…

Tu sembles oublier les objectifs de ce cours : faire comprendre l’abstraction, et rien de plus. La connaissance demandée en programmation fonctionnelle est minimale, j’explique la syntaxe de tous les exemples, et je laisse de côté ce qui n’est pas entièrement nécessaire à la compréhension (par exemple, la définition de la classe de types Monad ou les lois des monades). Dans ces conditions, un exemple qui mette en jeu de nombreux idiomes de programmation fonctionnelle, qui pis est dans 4 ou 5 langages différents, serait parfaitement hors de propos.

Dominus Carnufex

L'exemple en soi n'est peut-être pas le meilleur, c'était une proposition. Ce que je souhaitais dire, c'est que pour le lecteur qui vient d'un langage impératif du style Java, C++ (voir même Ocaml) peut avoir l'impression que les monades est seulement un ersatz : pour ton exemple de division, on pourrait utiliser les exceptions, our les E/S, on a les effets de bords etc…

A l'inverse, quelqu'un qui fait déjà de la programmation fonctionnelle va certainement rester sur sa faim vu la simplicité des exemples. C'est d'ailleurs quelque chose que je reproche aux nombreux articles introduisant les monades.

Cette discussion tourne en rond. Je te dis « Je veux que ce cours soit basique et que les aspects plus avancés soient abordés dans un autre cours1. », et tu me réponds « Ton cours est trop basique, on reste sur sa faim. ». Du coup, ne te déplaise, on va en rester là.


  1. Par exemple, le deuxième cours, celui qui doit aborder la classe de types Monad et les lois des monades, et qui serait précisément le lieu idéal pour un exemple plus étoffé de monade… 

+1 -0

J’ai intégré à la bêta le code C++ de gbdivers ainsi que le code Groovy de Javier, et fait quelques ajustements supplémentaires pour clarifier l’ensemble suite à des retours de Vayel en MP. La version actuelle est définitive et envoyée en validation, je n’attends donc plus de retours dessus : je la laisse en bêta pour qu’elle reste accessible jusqu’à la publication.

+0 -0

Oulalala j'avais donné ce pseudo-code à titre d'exemple (à la rache, comme on dit). Il est tout à fait faux :\

Alors d'abord c'est pas Groovy qui fait ça, mais Reactive Extensions. Qui est une déclinaison de RxJava, RxJS, RxScala, Rx.Net, RxSwift, …

Rien à voir avec le langage donc. Absolument pas, c'est une bibliothèque, qui expose un Observable qui m'avait lui même semblé être une monade.

C'était plus une réflexion qu'un exemple.

Pas sûr qu'il faille en faire étalage, mentionner Reactive Extensions devrait suffire, et surtout surtout pas tel que c'est présenté là (y'a des fautes dans les génériques, je ne suis pas certain du nom des primitives de l'API : genre lift et flatMap ça change parfois).

Désolé pour la confusion.

PS : et ça ne renvoie pas les bons types en plus… Non mais désolé c'est n'importe quoi mon exemple. Les vrais exemples sont ici : on voit que c'est pas lift mais from et pas flatMap mais map par exemple… Ouille.

+0 -0

Salut à tous,

Le tuto ayant été publié (merci informaticienzero ^^ ), je ferme la bêta. La prochaine étape de ce parcours sur les monades, c’est d’écrire les tutos manquants. Alors si vous vous sentez les compétences, surtout n’hésitez pas, je ne me les réserve pas ! En particulier, un tuto sur la classe de type Monad en Haskell, qui aborderait les lois des monades, serait plus que bienvenu. :)

+0 -0
Ce sujet est verrouillé.