12/26/22, 11:48 AM Chapitre 15. Programmation avec des monades https://book.rea

12/26/22, 11:48 AM Chapitre 15. Programmation avec des monades https://book.realworldhaskell.org/read/programming-with-monads.html 1/21 Real World Haskell Précédent Suivant Chapitre 15. Programmation avec des monades Pratique du golf : listes d'associations Les clients et les serveurs Web transmettent souvent les informations sous la forme d'une simple liste textuelle de paires clé-valeur. nom=Attila+%42The+Hun%42&occupation=Khan L'encodage est nommé application/x-www-form-urlencoded, et il est facile à comprendre. Chaque paire clé-valeur est séparée par un &caractère " ". Au sein d'une paire, une clé est une série de caractères, suivis d'un « =», suivis d'une valeur. Nous pouvons évidemment représenter une clé en tant que String , mais la spécification HTTP n'est pas claire quant à savoir si une clé doit être suivie d'une valeur. Nous pouvons saisir cette ambiguïté en représentant une valeur sous la forme d'un Maybe String . Si nous utilisons Nothingpour une valeur, alors il n'y avait pas de valeur présente. Si nous enveloppons une chaîne dans Just, alors il y avait une valeur. L'utilisation de Maybe nous permet de faire la distinction entre « aucune valeur » et « valeur vide ». Les programmeurs Haskell utilisent la liste des associations de noms pour le type [(a, b)] , où nous pouvons considérer chaque élément comme une association entre une clé et une valeur. Le nom provient de la communauté Lisp, où il est généralement abrégé en alist . Nous pourrions ainsi représenter la chaîne ci-dessus comme la valeur Haskell suivante. -- fichier : ch15/MovieReview.hs [("nom", Juste "Attila \"Le Hun\""), ("occupation", Juste "Khan")] Dans la section intitulée « Analyse d'une chaîne de requête codée en URL » , nous allons analyser une application/x-www-form-urlencodedchaîne et représenter le résultat sous la forme d'une liste de [(String, Maybe String)] . Disons que nous voulons utiliser l'une de ces listes pour remplir une structure de données. -- fichier : ch15/MovieReview.hs données MovieReview = MovieReview { revTitle :: Chaîne , revUser :: Chaîne , revReview :: Chaîne } Nous commencerons par insister sur l'évidence avec une fonction naïve. -- fichier : ch15/MovieReview.hs simpleReview :: [(String, Maybe String)] -> Peut-être MovieReview simpleReview alist = recherche de cas "titre" liste de de Bryan O'Sullivan, Don Stewart et John Goerzen Table des matières Sans commentaires Sans commentaires Sans commentaires Sans commentaires Sans commentaires 4 commentaires Sans commentaires 2 commentaires Sans commentaires 12/26/22, 11:48 AM Chapitre 15. Programmation avec des monades https://book.realworldhaskell.org/read/programming-with-monads.html 2/21 Juste (Juste titre@(_:_)) -> recherche de cas "utilisateur" liste de Juste (Juste utilisateur@(_:_)) -> recherche de cas "révision" liste de Juste (Juste révision@(_:_)) -> Juste (critique de l'utilisateur du titre MovieReview) _ -> Rien -- pas de révision _ -> Rien -- aucun utilisateur _ -> Rien -- pas de titre Il ne renvoie un MovieReview que si la liste contient toutes les valeurs nécessaires et qu'elles sont toutes des chaînes non vides. Cependant, le fait qu'elle valide ses entrées est son seul mérite : elle souffre beaucoup de « l' escalier » dont on a appris à se méfier, et elle connaît les détails intimes de la représentation d'un aliste. Puisque nous connaissons maintenant bien la monade Maybe , nous pouvons ranger l'escalier. -- fichier : ch15/MovieReview.hs peut-êtreReview alist = do titre <- lookup1 "titre" liste utilisateur <- lookup1 liste "utilisateur" review <- lookup1 liste "review" retour (critique de l'utilisateur du titre MovieReview) lookup1 key alist = liste de clés de recherche de cas de Juste (Juste s@(_:_)) -> Juste s _ -> Rien Bien que ce soit beaucoup plus ordonné, nous nous répétons encore. Nous pouvons profiter du fait que le MovieReviewconstructeur agit comme une fonction normale et pure en l' élevant dans la monade, comme nous l'avons vu dans la section intitulée « Mélanger du code pur et monadique » . -- fichier : ch15/MovieReview.hs liftedReview alist = liftM3 MovieReview (lookup1 liste "titre") (liste "utilisateur" lookup1) (lookup1 "révision" liste) Nous avons encore quelques répétitions ici, mais elles sont considérablement réduites et également plus difficiles à supprimer. Levage généralisé Bien que l'utilisation liftM3range notre code, nous ne pouvons pas utiliser une liftMfonction -family pour résoudre ce type de problème en général, car ils ne sont définis que liftM5par les bibliothèques standard. Nous pourrions écrire des variantes jusqu'au nombre qui nous plaisait, mais cela reviendrait à une corvée. Si nous avions un constructeur ou une fonction pure qui prenait, disons, dix paramètres et décidait de s'en tenir aux bibliothèques standard, vous pourriez penser que nous n'aurions pas de chance. Bien sûr, notre boîte à outils n'est pas encore vide. Dans Control.Monad, il existe une fonction nommée apavec une signature de type intéressante. ghci> :m +Control.Monad ghci> :type ap ap :: (Monade m) => m (a -> b) -> ma -> mb 4 commentaires Sans commentaires Sans commentaires 8 commentaires Sans commentaires 5 commentaires Sans commentaires Sans commentaires Sans commentaires Sans commentaires Sans commentaires 12/26/22, 11:48 AM Chapitre 15. Programmation avec des monades https://book.realworldhaskell.org/read/programming-with-monads.html 3/21 Vous pourriez vous demander qui mettrait une fonction pure à un seul argument dans une monade, et pourquoi. Rappelez-vous, cependant, que toutes les fonctions Haskell ne prennent en réalité qu'un seul argument, et vous commencerez à voir comment cela pourrait être lié au MovieReviewconstructeur. ghci> :type MovieReview MovieReview :: Chaîne -> Chaîne -> Chaîne -> MovieReview Nous pouvons tout aussi facilement écrire ce type sous la forme String -> (String -> (String -> MovieReview)) . Si nous utilisons plain old liftMpour remonter MovieReviewdans la Maybemonade, nous aurons une valeur de type Maybe (String -> (String -> (String -> MovieReview))) . Nous pouvons maintenant voir que ce type convient comme argument pour ap, auquel cas le type de résultat sera Maybe (String -> (String -> MovieReview)) . Nous pouvons passer ceci, à son tour, à ap, et continuer à enchaîner jusqu'à ce que nous nous retrouvions avec cette définition. -- fichier : ch15/MovieReview.hs liste apReview = MovieReview `liftM` lookup1 liste "titre" `ap` lookup1 "utilisateur" liste `ap` lookup1 "réviser" une liste Nous pouvons enchaîner des applications apcomme celle-ci autant de fois que nécessaire, contournant ainsi la liftMfamille de fonctions. Une autre façon utile de voir apest que c'est l'équivalent monadique de l' ($)opérateur familier : pensez à prononcer apcomme apply . Nous pouvons le voir clairement lorsque nous comparons les signatures de type des deux fonctions. ghci> :type ($) ($) :: (a -> b) -> a -> b ghci> :type ap ap :: (Monade m) => m (a -> b) -> ma -> mb En fait, apest généralement défini comme soit liftM2 idou liftM2 ($). À la recherche d'alternatives Voici une représentation simple des numéros de téléphone d'une personne. -- fichier : ch15/VCard.hs Contexte de données = Accueil | Mobile | Entreprise dérivant (Eq, Show) tapez Téléphone = Chaîne albulena = [(Maison, "+355-652-55512")] nils = [(Mobile, "+47-922-55-512"), (Entreprise, "+47-922-12-121"), (Maison, "+47-925-55-121"), (Entreprise, "+47-922-25-551")] twalumba = [(Entreprise, "+260-02-55-5121")] Supposons que nous voulions entrer en contact avec quelqu'un pour passer un appel personnel. Nous ne voulons pas de leur numéro professionnel et nous préférerions utiliser leur numéro personnel (s'ils en ont un) au lieu de leur numéro de mobile. -- fichier : ch15/VCard.hs onePersonalPhone :: [(Contexte, Téléphone)] -> Peut-être un téléphone onePersonalPhone ps = recherche de cas Accueil ps de Sans commentaires Sans commentaires Sans commentaires 7 commentaires Sans commentaires Sans commentaires 2 commentaires Sans commentaires Sans commentaires Sans commentaires Sans commentaires 12/26/22, 11:48 AM Chapitre 15. Programmation avec des monades https://book.realworldhaskell.org/read/programming-with-monads.html 4/21 Rien -> rechercher Mobile ps Juste n -> Juste n Bien sûr, si nous utilisons Maybe comme type de résultat, nous ne pouvons pas tenir compte de la possibilité qu'une personne ait plus d'un nombre répondant à nos critères. Pour cela, on passe à une liste. -- fichier : ch15/VCard.hs allBusinessPhones :: [(Contexte, Téléphone)] -> [Téléphone] allBusinessPhones ps = carte et numéros où nombres = filtre de cas (contextIs Business) ps de [] -> filtre (contextIs Mobile) ps ns -> ns contexteEst un (b, _) = a == b Notez que ces deux fonctions structurent leurs case expressions de manière similaire : une alternative gère le cas où la première recherche renvoie un résultat vide, tandis que l'autre gère le cas non vide. ghci> onePersonalPhone twalumba Rien ghci> onePersonalPhone albulena Juste "+355-652-55512" ghci> allBusinessPhones nils ["+47-922-12-121","+47-922-25-551"] Control.MonadLe module de Haskell définit une classe de types, MonadPlus , qui nous permet d'abstraire le modèle commun de nos caseexpressions. -- fichier : ch15/VCard.hs classe Monad m => MonadPlus m où mzero :: ma mplus :: ma -> ma -> ma La valeur mzeroreprésente un résultat vide, tandis que mpluscombine deux résultats en un seul. Voici les définitions standard de mzeroet mpluspour Maybe et les listes. -- fichier : ch15/VCard.hs instance MonadPlus [] où mzéro = [] plus = (++) instance MonadPlus Peut-être où mzero = Rien Rien `mplus` ys = ys xs `mplus` _ = xs Nous pouvons maintenant utiliser mpluspour nous débarrasser caseentièrement de nos expressions. Pour varier, récupérons une entreprise et tous les numéros de téléphone personnels. -- fichier : ch15/VCard.hs oneBusinessPhone :: [(Contexte, Téléphone)] -> Peut-être Téléphone oneBusinessPhone ps = lookup Business ps `mplus` lookup Mobile ps allPersonalPhones :: [(Contexte, Téléphone)] -> [Téléphone] allPersonalPhones ps = uploads/Science et Technologie/ chapitre-15-programmation-avec-des-monades-real-world-haskell.pdf

  • 12
  • 0
  • 0
Afficher les détails des licences
Licence et utilisation
Gratuit pour un usage personnel Attribution requise
Partager