Skip to content

Monades Avancées en Haskell

Bernard Sibanda edited this page Aug 2, 2025 · 1 revision

Monades Avancées en Haskell : Tutoriels Approfondis


Table des Matières

20. Monade  20.1 Idée de Base (définition sans détails)  20.2 Exemples Intuitifs  20.3 Extraire le Schéma  20.4 Définition Complète (avec tous les détails et lois)  20.5 Notation do en général

21. Monade Reader  21.1 Motivation  21.2 Stratégie de Liaison  21.3 Définition  21.4 Exemples

22. Monade Writer  22.1 Motivation  22.2 Stratégie de Liaison  22.3 Définition  22.4 Exemples

23. Monade State  23.1 Motivation  23.2 Stratégie de Liaison  23.3 Définition  23.4 Exemples

24. Fonctions Monadiques / Travailler avec des Monades  24.1 liftM  24.2 sequence et sequence_  24.3 mapM et mapM_  24.4 filterM  24.5 foldM

25. Transformers

Glossaire des Termes

Questions à Choix Multiples (avec Réponses)


20. Monade


20.1 Idée de Base (Définition Sans Détails)

Une monade est un schéma de conception en Haskell qui permet de chaîner des calculs tout en cachant certains soucis comme le contexte, les échecs, l’état ou les effets de bord. Les monades permettent d’écrire du code modulaire qui gère ces préoccupations de manière cohérente. Pensez à une monade comme un « constructeur de calculs » qui relie des étapes entre elles.


20.2 Exemples Intuitifs

Regardons trois monades en action : Maybe, [] (liste) et IO.

Exemple 1 : Monade Maybe – Division Sécurisée

Supposons que vous voulez diviser deux nombres, mais gérer la possibilité d'une division par zéro :

safeDiv :: Double -> Double -> Maybe Double
safeDiv _ 0 = Nothing
safeDiv x y = Just (x / y)

Utilisation :

result1 = safeDiv 10 2    -- Just 5.0
result2 = safeDiv 10 0    -- Nothing

Explication : Maybe est un contexte qui peut représenter une valeur ou « pas de valeur » (Nothing). Cela permet de signaler des erreurs sans lancer d’exception.


Exemple 2 : Monade Liste – Non-déterminisme

Supposons que vous voulez toutes les paires possibles de deux ensembles :

pairs :: [Int] -> [Int] -> [(Int, Int)]
pairs xs ys = do
  x <- xs
  y <- ys
  return (x, y)

Utilisation :

result = pairs [1,2] [3,4] -- [(1,3),(1,4),(2,3),(2,4)]

Explication : Chaque combinaison est générée automatiquement. La monade liste enchaîne les calculs pour chaque élément.


Exemple 3 : Monade IO – Entrée et Sortie Utilisateur

main :: IO ()
main = do
  putStrLn "Entrez votre nom :"
  name <- getLine
  putStrLn ("Bonjour, " ++ name ++ " !")

Explication : IO est un contexte qui modélise les effets de bord. L’utilisation de la notation do garantit que les actions sont effectuées dans l’ordre.


20.3 Extraire le Schéma

Voyons ce que ces exemples ont en commun :

  1. Ils enveloppent (« taguent ») une valeur :

    • Maybe a signifie « un a, ou rien ».
    • [a] signifie « zéro ou plusieurs a ».
    • IO a signifie « un a, produit par une action ».
  2. Ils offrent un moyen de chaîner les calculs :

    • Si vous avez une fonction qui produit une valeur dans le contexte, vous pouvez utiliser >>= pour enchaîner d'autres étapes, en respectant toujours le contexte.

Exemple 1 : Enchaîner des Maybe

sqrtMaybe :: Double -> Maybe Double
sqrtMaybe x
  | x < 0     = Nothing
  | otherwise = Just (sqrt x)

pipeline = do
  a <- safeDiv 10 2    -- Just 5
  b <- sqrtMaybe a     -- Just 2.236...
  return b
-- pipeline == Just 2.236...

Exemple 2 : Enchaîner des Listes

numbers = [1,2]
adders  = [10,100]

result = numbers >>= (\n -> adders >>= (\a -> return (n + a)))
-- [11,101,12,102]

Exemple 3 : Enchaîner des IO

main :: IO ()
main = getLine >>= (\name -> putStrLn ("Salut, " ++ name ++ " !"))

20.4 Définition Complète (avec tous les détails/lois)

Classe de Type Monad

class Applicative m => Monad m where
    (>>=)  :: m a -> (a -> m b) -> m b
    return :: a -> m a
  • >>= est « bind » : prend une valeur dans un contexte (m a) et une fonction qui prend une valeur normale et retourne une valeur dans le même contexte (a -> m b).
  • return élève une valeur simple dans le contexte.

Lois des Monades

  1. Identité à gauche : return a >>= ff a (Mettre une valeur dans le contexte et l’enchaîner équivaut à juste appliquer la fonction.)

  2. Identité à droite : m >>= returnm (Enchaîner avec return ne change pas le résultat.)

  3. Associativité : (m >>= f) >>= gm >>= (\x -> f x >>= g) (La façon de regrouper les calculs n’affecte pas le résultat.)


Exemple 1 : Vérification des Lois avec Maybe

f x = Just (x + 1)
m = Just 2

-- Identité à gauche
return 2 >>= f  -- Just 3
f 2             -- Just 3

-- Identité à droite
m >>= return    -- Just 2
m               -- Just 2

-- Associativité
((m >>= f) >>= f) == (m >>= (\x -> f x >>= f))

Exemple 2 : Vérification des Lois avec Liste

g x = [x, x*2]

-- Identité à gauche
return 3 >>= g   -- [3,6]
g 3              -- [3,6]

Exemple 3 : Vérification des Lois avec IO

main = do
  putStrLn "Entrez :"
  n <- readLn
  print (n * 2)

(Vous pouvez imaginer que la lecture et l’impression doivent respecter ces lois pour composer proprement.)


20.5 Notation do en général

La notation do est un sucre syntaxique pour enchaîner des opérations monadiques.

Exemple 1 : Utiliser do avec Maybe

pipeline = do
  a <- Just 3
  b <- Just 4
  return (a + b)
-- Just 7

Équivalent à :

Just 3 >>= (\a ->
  Just 4 >>= (\b ->
    return (a + b)))

Exemple 2 : Utiliser do avec Liste

pairs = do
  x <- [1,2]
  y <- [10,20]
  return (x, y)
-- [(1,10),(1,20),(2,10),(2,20)]

Exemple 3 : Utiliser do avec IO

main = do
  putStrLn "Quel est votre nom ?"
  name <- getLine
  putStrLn ("Bonjour, " ++ name)

Clone this wiki locally