Licence 3, semestre 5, 2013–2014 Programmation Fonctionnelle TD 2 (extra) 1 Listes Exercice 1 (Récursion Terminale vs Récursion Non-terminale) : Écrire des fonctions suivantes sur les listes. – length : calcule la longueur d’une liste. Exemple : length ["let" ;"toto" ;"42"; "hello"] = 4 length [true, false, false, true, true, false] = 6. Donner une version non-terminale, puis une version terminale. – list sigma : calcule la somme des éléments d’une liste d’entiers. Exemple : list sigma [1 ;2 ;3] = 6. Donner une version non-terminale, puis une version terminale. – make n v : crée une liste de taille n initialisée avec la valeur v. Exemple : make 3 "42" = ["42"; "42"; "42";] Donner une version non-terminale, puis une version terminale. – init n f : crée une liste de taille n initialisée à l’aide de la fonction f de telle manière que la i-ème élément de la liste est égal à f i (pour i = 0 .. (n-1)) . Exemple : init 3 (fun i -> i) = [0; 1; 2] Donner une version non-terminale, puis une version terminale. – range k m : crée une liste contenant des entiers de k à m dans l’ordre croissant. (si k > m , renvoie une liste vide) Exemple : range 2 5 = [2 ;3; 4; 5]. Exercice 2 (Fonctions de la Bibliothèque Standard List) : o mem : détermine si une liste contient une valeur donnée. Exemple : mem 27 [12 ;27 ;1] = true, mem 3 [12 ;27 ;1] = false. o append : concatène deux listes. Exemple : append [1 ;2 ;3] [4 ;5] = [1 ;2 ;3 ;4 ;5]. Donner uniquement une version non-terminale. o flatten : aplanir d’un niveau une liste de listes. Exemple : flat [[2] ;[] ;[3 ;4 ;5]] = [2 ;3 ;4 ;5]. o map : la fonction telle que map f [a1 ;... ;an ] = [f(a1 ) ;... ;f(an )]. o exist : teste si au moins un des éléments de la liste satisfait une condition passée en argument. Exemple : exist (fun x -> if x = 0 then true else false) [1;2;0;4] = true 1 Exercice 3 (palindromes) : Écrire des fonctions suivantes sur les listes. – last : trouve le dernier élément d’une liste. Si la liste est vide, lever l’exception Empty list définie précédemment. Exemple : last [12 ;27 ;14] = 14 – drop last : renvoie la liste passée en argument privée du dernier élément. Exemple : drop last [12 ;27 ;14] = [12 ;27] – palindrome : teste si la liste passée en en argument est un palindrome Exemple : palindrome [] = true, palindrome [1 ;2] = false, palindrome [1 ;2 ;3 ;2 ;1] = true Donner une version non-terminale (en utilisant les deux fonctions précédentes). Quelle est la complexité de la solution ? o rev : inverse l’ordre des éléments d’une liste. Exemple : rev [1 ; 2 ; 3] = [3 ; 2 ; 1]. Donner une version non-terminale (en utilisant les deux fonctions précédentes last et drop last). Quelle est la complexité de la solution ? Donner une version terminale. Quelle est la complexité maintenant ? – palindrome : Donner une version de palindrome non-terminale, en utilisant la fonction rev définie précédemment). Quelle est la complexité de la solution ? Exercice 4 (tri par insertion) : Dans cet exercice, nous allons écrire le tri par insertion, sous la forme d’une fonction opérant sur des listes d’entiers, c’est-à-dire ayant le type int list -> int list. 1. Écrire une fonction insertion : int -> int list -> int list qui insère un élément dans une liste d’entiers supposée triée en ordre croissant. 2. Écrire une fonction insertion sort : int list -> int list qui réalise le tri par insertion d’une liste d’entiers. On rappelle que cela consiste à extraire le premier élément de la liste, à trier récursivement le reste de la liste, puis à insérer l’élément isolé (avec la fonction insertion). 3. Pour tester votre fonction de tri, écrivez une fonction is sorted : int list -> bool qui retourne true si la liste passée en argument est triée dans l’ordre croissant Exercice 5 (tri rapide) : Dans cet exercice, nous allons écrire le tri rapide (Quicksort) inventé par le chercheur britannique C.A.R. Hoare. 1. Écrire une fonction partition : int -> int list -> int list * int list qui prend en argument un entier x et une liste d’entiers l et renvoie une paire de listes (l1,l2) telle que l1 (resp. l2) contient les éléments de l plus petits (resp. plus grands) que x. 2 2. Écrire une fonction quicksort : int list -> int list réalisant le tri rapide (quicksort). On rappelle que le principe consiste à isoler un élément particulier de la liste (ici le premier), à partionner les éléments restants en utilisant la fonction partition ci-dessus, à trier récursivement les deux listes obtenues, et enfin à recoller les morceaux. Pour cette dernière étape on pourra utiliser la fonction de bibliothèque List.append qui effectue la concaténation de deux listes (elle se note également @ de manière infixe). 2 Ordre Supérieur 1. Écrire une fonction forall : (int -> bool) -> int array -> bool telle que forall p t vérifie que p t.(i) renvoie bien true pour toutes les cases i de t. 2. Qu’est-ce qui est affiché dans le terminal après avoir tapé la déclaration suivante dans le top-level ? # let rec test1 x = let f = print_string "."; fun y -> y - 1 in if x = 0 then 1 else test1 (f x) ;; Même question après avoir tapé l’expression suivante : # test1 4;; 3. Comparer vos réponses à la question précédente si on considère maintenant la déclaration suivante : # let rec test2 = let f = print_string "."; fun y -> y - 1 in fun x -> if x = 0 then 1 else test2 (f x) ;; et l’expression suivante # test3 4;; 4. Donner le type des fonctions suivantes : let f = let x = ref 3 in fun () -> x let g = fun () -> let x = ref 3 in x 5. Quelles sont les différences entre ces deux fonctions ? 6. Donner les résultats renvoyées (dans le top-level ) par les déclarations et/ou expressions suivantes : # # # # # let a = f () ;; let b = f () ;; a = b ;; a == b ;; incr a; !b ;; 3 # # # # # let c = g () ;; let d = g () ;; c = d ;; c == d ;; incr c; !d ;; 7. Soit la fonction plus définie de la manière suivante : # let plus x y = x+y ;; val plus : int -> int -> int = <fun> Quelle différence y-a-t’il avec la déclaration suivante ? # let plus (x, y) = x+y ;; 4