Principes de Programmation TP5 22 mars 2017 On rappelle qu’il y a deux syntaxes possibles pour utiliser les monades : – La première est plus “fonctionnelle”. Elle consiste à travailler comme s’il n’y avait pas de monade et de rajouter des bindings =<< et des return là où il faut. – La seconde est plus “impérative”, c’est la “do-construction”. En fait, les deux sont très similaires. Au lieu d’utiliser une application f=<<arg dans l’environnement de la monade (avec f::a->m b et arg:m a), la do-construction va utiliser une variable intermédiaire à valeur dans la monade : do x <- arg f x ici, x::a est calculé sans considérer la monade. L’effet de la monade est appliqué à l’utilisation de la flèche <-. Exercice 1 (La monade IO). Écrivez le programme suivant : 1 import import main :: IO main = do putStrLn t <start <end <putStrLn Control.DeepSeq System.CPUTime () "Pour quelle taille de liste voulez-vous faire un test ?" getLine getCPUTime deepseq (map (+1) [1..(read t)]) getCPUTime ("finit en "++ show(end-start)) 1. Selon vous, que fait-il ? (Dans un premier temps, ignorez l’instruction deepseq). 2. L’instruction deepseq :: a -> IO b -> IO b calcule le résultat du premier argument, l’oublie puis calcule le second. Quel est l’intérêt ici ? On notera que cet opérateur est à utiliser avec parcimonie. 1. Attention à l’indentation ! 1 3. Utilisez ghci pour avoir les type de getLine,de getCPUTime et de putStrLn. 4. Essayez de comprendre ce qui se passe, puis faites quelques essais. À noter que “main” à toujours le type IO (). Cela signifie qu’il ne rend aucun résultat dans haskell, mais que tout ce qui est calculé est envoyé dans l’environnement (par exemple affiché sur la sortie standard). 5. Réécrire le même programme en utilisant des bindings =<< et des return Exercice 2 (Suite du TD). Essayez de compiler les exemples vus en TD (n’oubliez pas de changer les noms pour éviter les conflits). Exercice 3 (La monade des listes). 1. Écrivez une fonction fixerVal :: Eq a => (a->b) -> a -> b -> (a -> b) qui prend trois arguments : une fonction (f::a->b), une abscisse x::a et une ordonnée y:b et qui rend une fonction f’::a->b qui est la même que f excepté pour x où elle vaut y. 2. En l’utilisant, écrivez une fonction : toutesVal :: Eq a, Enum b, Bounded b => (a->b) -> a -> [a -> b] qui prend une fonction (f::a->b), une abscisse x::a et rend la liste des fonctions obtenues faisant varier cette abscisse sur toutes ses valeurs possibles. 2 3. En utilisant le binding (=<<) :: (a->[b]) -> [a] -> b, écrivez la fonction : toutesValListe :: Eq a, Enum b, Bounded b => (a->b) -> [a] -> [a -> b] qui énumère toutes les valeurs possibles en changeant les éléments de la liste de a. 4. Écrivez la fonction valVerite :: Pred -> [Int -> Bool] qui liste toutes les valeurs de vérité que l’on peut appliquer à un prédicat. 5. Écrivez une version avec une do-construction. 2. Indice : utilisez un map :: (b− > a− > b)− > [b]− > [a− > b]. 2