Bonjour,
J'avais fait un exposé pour expliquer ça entre autres, je ne sais pas si c'est tellement compréhensible sans les explications données à l'oral mais les slides sont là : http://www.sylvain-henry.info/home/data/uploads/talks/shenry-2013-02-05-haskell-intro.pdf (à partir du 20e slide).
* Contexte
Dans un langage fonctionnel, on n'utilise pas de variable globale donc pour qu'il y ait un contexte il faut le passer explicitement en entrée des fonctions et le renvoyer en sortie (en plus d'autres valeurs potentiellement) :
f :: ... -> Context -> (Context, ...)
pour ne pas écrire à chaque fois les types "Context", on peut faire :
type M a = Context -> (Context, a)
et réécrire :
f :: ... -> M a
Il ne reste plus qu'à définir la composition pour les fonctions de ce type de sorte que le contexte soit passé de la sortie de la première fonction à l'entrée de l'autre :
(>>=) :: M a -> (a -> M b) -> M b
(>>=) f g = \ctx -> let (ctx2, a) = f ctx in g a ctx2
Pour créer une fonction de type "M a" à partir d'un "a", on définit la fonction :
return :: a -> M a
return x = \ctx -> (ctx,x)
* IO
Dans le cas des IO, le "contexte" est le "monde" (extérieur au programme). La fonction main a le type suivant :
main :: IO ()
soit
main :: World -> (World, () )
Donc on peut composer des fonctions qui ont des effets de bord avec (>>=) de sorte que ce soit correct d'un point de vue types sans jamais dire exactement ce que représente le type World. Les opérations s'exécutent en séquence puisque chaque opération "attend de récupérer le monde renvoyé par l'opération qui la précède" (du moins c'est l'idée). Il n'y a aucun moyen pour le programme de créer un objet de type World donc toutes les opérations s'enchainent forcément à partir de celui passé à "main".
* Monades
Les monades sont juste une généralisation du mécanisme décrit ci-dessus (en gros), c'est pourquoi ils sont adaptés. La typeclass Monad implique la typeclass Applicative (l'inverse n'est pas vrai) et on aurait pu utiliser Applicative à la place de Monad dans le cas des IOs. Ça a même été suggéré sur la mailing-list haskell-cafe il n'y a pas si longtemps si je me souviens bien.