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 :
Noneounull→ 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
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
Analogie :
- Boîte fermée avec un cadeau →
Just valeur - Boîte vide →
Nothing
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 :
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 :
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 :
🛠️ 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 :
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 ?
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
💡 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 ! 💪