Skip to content

2. Le Type Maybe

🎯 Le Problème

Que Retourner Quand Ça Échoue ?

-- Comment écrire cette fonction ?
dernierElement : Liste a -> ???
dernierElement lst = ...

-- Problème : Que retourner si la liste est vide ?
dernierElement Vide = ???  -- Pas d'élément à retourner !

En d'autres langages :

  • Python/Java : None ou null → crashes possibles
  • C : Valeur spéciale (-1, 0) → ambiguë
  • Exceptions : Lourd et imprévisible

En Elm : Le type Maybe !


📦 Définition de Maybe

Le Type

type Maybe a
    = Nothing       -- Absence de valeur
    | Just a        -- Présence d'une valeur de type a

Lecture : Un Maybe a est SOIT Nothing (rien), SOIT Just une valeur de type a.

Exemples de Valeurs

-- Maybe Int
Nothing             -- Pas d'entier
Just 42             -- L'entier 42

-- Maybe String
Nothing             -- Pas de chaîne
Just "hello"        -- La chaîne "hello"

-- Maybe Bool
Nothing             -- Pas de booléen
Just True           -- Le booléen True

💡 Intuition

Maybe = Boîte Optionnelle

Just 5       -- Boîte contenant 5
Nothing      -- Boîte vide

Analogie :

  • Boîte fermée avec un cadeauJust valeur
  • Boîte videNothing

En Comparaison avec d'Autres Langages

Langage Équivalent Problème
Python None Pas typé, crash possible
Java null NullPointerException
JavaScript null/undefined Confusion
Rust Option<T> Même concept ! ✅
Haskell Maybe a Identique ✅
Elm Maybe a Sûr à la compilation ✅

🔍 Utilisation avec les Listes

Exemple 1 : premier (head)

-- Renvoie le premier élément d'une liste
premier : Liste a -> Maybe a
premier lst =
    case lst of
        Vide -> Nothing                    -- Pas d'élément
        Cons tete queue -> Just tete       -- On a un élément !

Utilisation :

premier [1, 2, 3]
--> Just 1

premier []
--> Nothing

Exemple 2 : dernierElement

-- Renvoie le dernier élément d'une liste
dernierElement : Liste a -> Maybe a
dernierElement lst =
    case lst of
        Vide -> Nothing                              -- Liste vide
        Cons tete Vide -> Just tete                  -- Un seul élément
        Cons _ queue -> dernierElement queue         -- Continue la recherche

Utilisation :

dernierElement [1, 2, 3]
--> Just 3

dernierElement []
--> Nothing

dernierElement [42]
--> Just 42

Trace d'exécution :

dernierElement [1, 2, 3]
= dernierElement [2, 3]          (pas le dernier)
= dernierElement [3]             (pas le dernier)
= Just 3                         (un seul élément !)


🎨 Pattern Matching sur Maybe

Déconstruire un Maybe

case monMaybe of
    Nothing -> ...       -- Cas où il n'y a rien
    Just valeur -> ...   -- Cas où on a une valeur

Exemple : Afficher un Résultat

afficherResultat : Maybe Int -> String
afficherResultat resultat =
    case resultat of
        Nothing -> "Aucun résultat"
        Just n -> "Le résultat est : " ++ String.fromInt n

Utilisation :

afficherResultat (Just 42)
--> "Le résultat est : 42"

afficherResultat Nothing
--> "Aucun résultat"


🛠️ Fonctions Utiles sur Maybe

Maybe.withDefault : Valeur par Défaut

-- Si Nothing, utilise la valeur par défaut
Maybe.withDefault : a -> Maybe a -> a

-- Exemples
Maybe.withDefault 0 (Just 5)
--> 5

Maybe.withDefault 0 Nothing
--> 0

Maybe.withDefault "inconnu" (Just "Alice")
--> "Alice"

Maybe.withDefault "inconnu" Nothing
--> "inconnu"

Utilisation pratique :

-- Obtenir le premier élément ou 0 par défaut
premierOuZero : Liste Int -> Int
premierOuZero lst =
    premier lst
        |> Maybe.withDefault 0

premierOuZero [1, 2, 3]
--> 1

premierOuZero []
--> 0

Maybe.map : Transformer la Valeur

-- Applique une fonction si Just, sinon reste Nothing
Maybe.map : (a -> b) -> Maybe a -> Maybe b

-- Exemples
Maybe.map (\x -> x * 2) (Just 5)
--> Just 10

Maybe.map (\x -> x * 2) Nothing
--> Nothing

Maybe.map String.length (Just "hello")
--> Just 5

Cas d'usage :

-- Doubler le premier élément
doublerPremier : Liste Int -> Maybe Int
doublerPremier lst =
    premier lst
        |> Maybe.map (\x -> x * 2)

doublerPremier [5, 10, 15]
--> Just 10

doublerPremier []
--> Nothing


⚠️ Erreurs Courantes

Erreur 1 : Oublier le Just

-- ❌ ERREUR
premier : Liste a -> Maybe a
premier lst =
    case lst of
        Vide -> Nothing
        Cons tete queue -> tete  -- Manque Just !

-- ✅ CORRECT
premier : Liste a -> Maybe a
premier lst =
    case lst of
        Vide -> Nothing
        Cons tete queue -> Just tete

Erreur 2 : Oublier le Cas Nothing

-- ❌ ERREUR : Pattern matching incomplet
utiliser : Maybe Int -> Int
utiliser m =
    case m of
        Just x -> x * 2
        -- Manque le cas Nothing !

-- ✅ CORRECT
utiliser : Maybe Int -> Int
utiliser m =
    case m of
        Just x -> x * 2
        Nothing -> 0  -- Valeur par défaut

Erreur 3 : Retourner Nothing au Lieu de Just Nothing

-- Type Maybe (Maybe a) : un Maybe dans un Maybe !

trouverPuis : (a -> Maybe b) -> Maybe a -> Maybe (Maybe b)
trouverPuis f m =
    case m of
        Nothing -> Nothing           -- Pas de valeur de base
        Just x -> Just (f x)         -- Just du résultat (qui peut être Nothing)

-- Exemple
trouverPuis premier (Just [1, 2, 3])
--> Just (Just 1)

trouverPuis premier (Just [])
--> Just Nothing  -- ⚠️ Pas juste Nothing !

trouverPuis premier Nothing
--> Nothing

🔗 Chaîner des Maybe

Problème : Maybe Imbriqués

-- Obtenir le premier élément du dernier élément (si c'est une liste de listes)

-- Version naïve
getPremierDuDernier : Liste (Liste a) -> Maybe (Maybe a)
getPremierDuDernier listes =
    case dernierElement listes of
        Nothing -> Nothing
        Just derniereListe -> Just (premier derniereListe)

-- Résultat : Maybe (Maybe a) 😕

Solution : Maybe.andThen

-- Maybe.andThen : (a -> Maybe b) -> Maybe a -> Maybe b
-- "Chaîne" les Maybe sans les imbriquer

getPremierDuDernier : Liste (Liste a) -> Maybe a
getPremierDuDernier listes =
    dernierElement listes
        |> Maybe.andThen premier

-- Exemples
getPremierDuDernier [[1, 2], [3, 4], [5, 6]]
--> Just 5  (premier de [5, 6])

getPremierDuDernier [[1, 2], [3, 4], []]
--> Nothing  (dernier = [], qui n'a pas de premier)

getPremierDuDernier []
--> Nothing  (pas de dernier)

🎓 Exemple Complet : minimum

Trouver le Minimum d'une Liste

-- Renvoie le plus petit élément (s'il existe)
minimum : Liste comparable -> Maybe comparable
minimum lst =
    case lst of
        Vide -> Nothing
        Cons premier reste ->
            case minimum reste of
                Nothing -> Just premier          -- Premier est le seul élément
                Just minReste ->
                    if premier < minReste then
                        Just premier             -- Premier est plus petit
                    else
                        Just minReste            -- minReste est plus petit

Utilisation :

minimum [3, 1, 4, 1, 5]
--> Just 1

minimum [42]
--> Just 42

minimum []
--> Nothing

Trace d'exécution :

minimum [3, 1, 4]
= case minimum [1, 4] of          -- 3 vs min([1,4])
    Just 1 -> if 3 < 1 then Just 3 else Just 1
= Just 1

minimum [5]
= case minimum [] of              -- 5 vs rien
    Nothing -> Just 5
= Just 5


💪 Exercices (À Faire)

Exercice 1 : elementA

Écris une fonction qui retourne l'élément à la position n (commence à 0).

elementA : Int -> Liste a -> Maybe a

-- Exemples attendus
elementA 0 [1, 2, 3]  --> Just 1
elementA 2 [1, 2, 3]  --> Just 3
elementA 5 [1, 2, 3]  --> Nothing
elementA -1 [1, 2, 3] --> Nothing

Indice : Utilise drop et premier.

Exercice 2 : maximum

Écris une fonction qui retourne le plus grand élément.

maximum : Liste comparable -> Maybe comparable

-- Exemples attendus
maximum [3, 1, 4, 1, 5]  --> Just 5
maximum []               --> Nothing

Indice : Similaire à minimum, mais avec > au lieu de <.

Exercice 3 : trouver

Écris une fonction qui retourne le premier élément satisfaisant un prédicat.

trouver : (a -> Bool) -> Liste a -> Maybe a

-- Exemples attendus
trouver (\x -> x > 3) [1, 2, 3, 4, 5]  --> Just 4
trouver (\x -> x > 10) [1, 2, 3]       --> Nothing

🎯 Pourquoi Maybe est Important ?

1. Sécurité à la Compilation

-- ❌ Impossible en Elm
x = premier []
y = x + 1  -- Erreur de compilation !

-- ✅ Elm force à gérer le cas Nothing
x = premier []
y = case x of
    Just n -> n + 1
    Nothing -> 0

Pas de crash à l'exécution ! 🛡️

2. Code Explicite

-- La signature dit tout
dernierElement : Liste a -> Maybe a
--                          ↑
--                          "Peut échouer !"

-- vs en Python
def last_element(lst):  # Peut retourner None... ou crasher ?
    ...

3. Forcer à Penser aux Cas d'Erreur

-- Tu DOIS gérer Nothing
case premier maListe of
    Nothing -> ...  -- Obligé de penser à ce cas
    Just x -> ...

📊 Maybe vs Autres Approches

Approche Problème Elm avec Maybe
Valeur spéciale (-1, "") Ambiguë Explicite avec type
Exception Invisible, peut crasher Visible dans signature
null/None Pas vérifié à la compilation Vérifié !
Maybe Aucun ✅ Parfait

🔄 Pattern Récurrent

Le Schéma Maybe

maFonction : EntréePeut-ÊtreVide -> Maybe Résultat
maFonction entree =
    case entree of
        CasVide -> Nothing                    -- Échec
        CasNonVide données -> Just résultat   -- Succès

Exemples :

  • Liste vide → Nothing
  • Division par zéro → Nothing
  • Clé inexistante dans dictionnaire → Nothing
  • Parsing échoué → Nothing

✅ Résumé

Qu'est-ce que Maybe ?

type Maybe a = Nothing | Just a
  • Nothing : Absence de valeur (échec, vide, erreur)
  • Just valeur : Présence d'une valeur

Quand Utiliser Maybe ?

Utilise Maybe a pour le type de retour d'une fonction quand :

  • ✅ La fonction peut échouer
  • ✅ Il peut ne pas y avoir de résultat
  • ✅ L'entrée peut être vide

Fonctions Clés

-- Valeur par défaut
Maybe.withDefault : a -> Maybe a -> a

-- Transformer
Maybe.map : (a -> b) -> Maybe a -> Maybe b

-- Chaîner
Maybe.andThen : (a -> Maybe b) -> Maybe a -> Maybe b

Le Pattern

case monMaybe of
    Nothing -> -- Gérer l'absence
    Just valeur -> -- Utiliser la valeur

💡 Conseil Final

Si ta fonction peut "échouer" ou "ne rien retourner", utilise Maybe !

-- ✅ Bon
premier : Liste a -> Maybe a

-- ❌ Mauvais (impossible de représenter l'échec)
premier : Liste a -> a  -- Et si la liste est vide ???

Maybe = Sécurité + Clarté + Pas de surprise ! 🎯


📚 Pour Aller Plus Loin

Une fois que tu maîtrises Maybe, tu peux découvrir Result : Pour les erreurs avec message.

Mais pour l'instant, Maybe est déjà très puissant ! 💪