diff --git a/labo07/Makefile b/labo07/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..2f11be640726d2d6ccce655fae59c7c357cf05f6 --- /dev/null +++ b/labo07/Makefile @@ -0,0 +1,7 @@ +README.html: README.md + pandoc -o README.html README.md + +.PHONY: clean + +clean: + rm -f *.html diff --git a/labo07/README.md b/labo07/README.md new file mode 100644 index 0000000000000000000000000000000000000000..f202978489cada2135ca137890238990c00d3d1f --- /dev/null +++ b/labo07/README.md @@ -0,0 +1,121 @@ +# Laboratoire 7: Entrées et sorties, révision + +## 1 - Entrées et sorties + +Écrivez un module Haskell appelé `TrimTrailing.hs` qui prend en entrée +n'importe quel fichier texte, qui supprime les espaces en fin de ligne (en +anglais, on les appelle *trailing spaces*) et qui affiche le résultat sur +`stdout`. + +On s'attend donc à ce que la commande +```haskell +runhaskell TrimTrailing.hs dirty.txt > clean.txt +``` +recopie le fichier `dirty.txt` tel quel dans le fichier `clean.txt`, à +l'exception des espaces superflues qui ont été supprimées. + +## 2 - Récursivité + +Proposez une implémentation (récursive) des fonctions suivantes (sans faire +appel à d'autres fonctions, comme `map`, `filter`, etc.): +```haskell +-- "Zippe" deux listes +zip :: [a] -> [b] -> [(a,b)] + +-- "Zippe" deux listes en appliquant une fonction +zipWith :: (a -> b -> c) -> [a] -> [b] -> [c] + +-- Indique si la première liste est préfixe de la deuxième +isPrefixOf :: Eq a => [a] -> [a] -> Bool +``` + +## 3 - La fonction `iterate` + +Une fonction d'ordre supérieur très utile en Haskell est la fonction +```haskell +iterate :: (a -> a) -> a -> [a] +``` +qui applique de façon répétée une fonction à une valeur en stockant le résultat +dans une liste. Noter que la liste résultante est infinie. + +Par exemple, si on souhaite calculer les 10 premières puissances de 3, il +suffit d'écrire +```haskell +>>> take 10 $ iterate (*3) 1 +[1,3,9,27,81,243,729,2187,6561,19683] +``` + +## 3.1 - La fonction `iterateWhile` + +Donnez l'implémentation d'une fonction +```haskell +iterateWhile :: (a -> a -> Bool) -> (a -> a) -> a -> [a] +``` +qui itère une fonction sur un élément jusqu'à ce qu'une certaine condition soit +satisfaite. + +Par exemple, si nous souhaitons récupérer les puissances de 3 tant que l'écart +entre deux puissances sucessives est moins de 1000, on écrirait +```haskell +>>> iterateWhile (\x y -> y - x < 1000) (*3) 1 +[1,3,9,27,81,243,729] +``` + +*Aide*: Une solution possible peut être obtenue en complétant la déclaration +suivante: +```haskell +iterateWhile :: (a -> a -> Bool) -> (a -> a) -> a -> [a] +iterateWhile f g x + | "condition" = une expression qui appelle iterateWhile + | otherwise = le cas de base +``` + +## 3.2 - La fonction `iterateUntilEqual` + +En utilisant la fonction `iterateWhile` définie plus haut, proposez une fonction +```haskell +iterateUntilEqual :: Eq a => (a -> a) -> a -> [a] +``` +qui a le même comportement que `iterate`, mais qui stoppe l'itération +lorsqu'une valeur est égale à la suivante dans le résultat. + +Par exemple, supposons que nous ayons une fonction qui calcule les différences +possibles entre toutes les paires d'éléments d'un ensemble: +```haskell +allDifferences :: Set Int -> Set Int +allDifferences s = s `union` fromList [abs (x - y) | x <- elems s, y <- elems s] +``` + +Alors on aurait le comportement suivant: +```haskell +>>> iterateUntilEqual allDifferences $ fromList [80,5] +[fromList [5,80],fromList [0,5,75,80],fromList [0,5,70,75,80],fromList [0,5,10,65,70,75,80],fromList [0,5,10,15,55,60,65,70,75,80],fromList [0,5,10,15,20,25,40,45,50,55,60,65,70,75,80],fromList [0,5,10,15,20,25,30,35,40,45,50,55,60,65,70,75,80]] +>>> last $ iterateUntilEqual allDifferences $ fromList [80,5] +fromList [0,5,10,15,20,25,30,35,40,45,50,55,60,65,70,75,80] +``` +Autrement dit, si on prend toutes les différences possibles entre éléments d'un +ensemble et qu'on répète le processus jusqu'à ce qu'il y ait stagnation (la +liste obtenue est la même qu'à l'étape précédente), alors on arrête +l'itération. + +Ce patron est fréquent rencontré en informatique: on répète un algorithme +jusqu'à ce qu'il y ait stagnation. C'est d'ailleurs souvent une condition +d'arrêt de multiples algorithmes, notamment les algorithmes génétiques. + +## 3.3 - La fonction `ancesters` + +Récupérez le module [`Simpsons.hs`](Simpsons.hs) disponible dans ce dépôt. + +En faisant appel à la fonction `iterateUntilEqual` définie précédemment, +complétez l'implémentation des fonctions `parents'` et `ancesters`. En +particulier, on s'attend aux résultats suivants: +```haskell +>>> parents' ["Lisa", "Homer"] +["Homer","Marge","Abraham","Mona"] +>>> ancesters "Lisa" +["Homer","Marge","Abraham","Mona","Clancy","Jackie","Orville","Yuma","Willard","Theodora"] +``` + +*Note*: Il est possible de définir la fonction `ancesters` sans faire appel à +la fonction `iterateUntilEqual`, mais il s'agit d'un excellent exercice pour +voir si vous comprenez bien comment utiliser les fonctions d'ordre supérieur. diff --git a/labo07/Simpsons.hs b/labo07/Simpsons.hs new file mode 100644 index 0000000000000000000000000000000000000000..2c461d9960f279a6677fe84acdacb78481717d76 --- /dev/null +++ b/labo07/Simpsons.hs @@ -0,0 +1,31 @@ +module Simpsons where + +import qualified Data.Map.Strict as Map +import Data.Set + +type Person = String + +parents = Map.fromList [("Bart", ["Homer", "Marge"]), + ("Lisa", ["Homer", "Marge"]), + ("Maggie", ["Homer", "Marge"]), + ("Marge", ["Clancy", "Jackie"]), + ("Homer", ["Abraham", "Mona"]), + ("Herb", ["Abraham"]), + ("Patty", ["Clancy", "Jackie"]), + ("Selma", ["Clancy", "Jackie"]), + ("Abraham", ["Orville", "Yuma"]), + ("Yuma", ["Willard", "Theodora"])] + +-- | Retourne tous les parents de toutes les personnes données +parents' :: [Person] -> [Person] +parents' = error "À compléter" + +-- | Retourne tous les ancêtres d'une personne donnée +-- +-- On dit que x est un ancêtre de y si une des deux conditions suivantes est +-- respectée: +-- +-- * x est un parent direct de y +-- * x est l'ancêtre d'un parent de y +ancesters :: Person -> [Person] +ancesters = error "À compléter"