• Aucun résultat trouvé

Traitement de liste (8)

N/A
N/A
Protected

Academic year: 2022

Partager "Traitement de liste (8)"

Copied!
42
0
0

Texte intégral

(1)

c 2006 Marc Feeley IFT2030 page 139

Traitement de liste (8)

Les listes peuvent représenter des ensembles

Par exemple: (rouge jaune bleu) = ensemble des couleurs primaires

Tester l’appartenance à un ensemble 1. (member 5 ’()) => #f

2. (member 5 ’(5 7)) => (5 7)

3. (member 5 ’(3 5 7)) = (member 5 ’(5 7)) (define member ; note: pr´ed´efinie

(lambda (x lst) (if (null? lst)

#f

(if (equal? x (car lst)) lst

(member x (cdr lst))))))

(2)

c 2006 Marc Feeley IFT2030 page 140

Traitement de liste (9)

Pour une évaluation conditionnelle à plusieurs branches on se sert normalement de la forme spéciale “cond”:

(cond

{

(hexpr1i hexpr2i)

}

(else hexpr3i))

Cela évite d’imbriquer l’expression trop profondément:

(define member

(lambda (x lst)

(cond ((null? lst)

#f)

((equal? x (car lst)) lst)

(else

(member x (cdr lst))))))

(3)

c 2006 Marc Feeley IFT2030 page 141

Traitement de liste (10)

Les listes peuvent représenter des dictionnaires (structure associant une donnée à une clé)

Déf: une liste d’association c’est une liste de paires de la forme (hcl ´ei . hdonn ´eei)

Exemple: inventaire d’un épicier

((pomme . 100) (orange . 0))

Exemple: échelle de prix

((1 . 2.55) (10 . 2.15) (100 . 2.03))

(4)

c 2006 Marc Feeley IFT2030 page 142

Traitement de liste (11)

Recherche dans une liste d’association

• Liste + clé => donnée

• Comment indiquer clé pas trouvée?

• Retourner plutôt #f ou paire contenant la clé et donnée

(define assoc ; note: pr´ed´efinie (lambda (cle lst)

(if (null? lst)

#f

(let ((paire (car lst)))

(if (equal? cle (car paire)) paire

(assoc cle (cdr lst)))))))

(5)

c 2006 Marc Feeley IFT2030 page 143

Traitement de liste (12)

Renverser une liste

1. (reverse ’()) => ()

2. (reverse ’(a b c)) =

(append (reverse ’(b c)) (list ’a)) (define reverse

(lambda (lst)

(if (null? lst)

’()

(append (reverse (cdr lst)) (list (car lst))))))

(6)

c 2006 Marc Feeley IFT2030 page 144

Traitement de liste (13)

Soit R(n) = nombre de paires créées par l’appel (reverse x) où L(x) = n

R(0) = 0

R(n) = n + R(n − 1), si n > 0

R(n) = n + (n − 1) + ... + 0 = n(n + 1)/2

C’est beaucoup d’espace pour un résultat contenant n paires!

(7)

c 2006 Marc Feeley IFT2030 page 145

Forme itérative (1)

Souvent, une meilleure solution peut être obtenue en s’attaquant à un problème plus général

(append-rev x y) = (append (reverse x) y)

1. (append-rev ’() ’(b a)) => (b a) 2. (append-rev ’(c d e) ’(b a)) =

(append-rev ’(d e) ’(c b a))

(8)

c 2006 Marc Feeley IFT2030 page 146

Forme itérative (2)

Définition:

(define append-rev

(lambda (lst1 lst2) (if (null? lst1)

lst2

(append-rev (cdr lst1)

(cons (car lst1) lst2))))) (define reverse

(lambda (lst)

(append-rev lst ’())))

Crée exactement n paires lorsque L(lst) = n

(9)

c 2006 Marc Feeley IFT2030 page 147

Forme itérative (3)

Exemple avec factorielle

(mult-fact n m) = (* (fact n) m)

1. (mult-fact 0 100) => 100

2. (mult-fact 3 100) = (mult-fact 2 300) (define mult-fact

(lambda (n m) (if (= n 0)

m

(mult-fact (- n 1) (* n m))))) (define fact

(lambda (n)

(mult-fact n 1)))

(10)

c 2006 Marc Feeley IFT2030 page 148

Forme itérative (4)

Déf: une expression E est en position terminale par rapport à une fonction F si le résultat de l’évaluation de E est retourné directement comme résultat de F

(define fact (lambda (n)

(if (< n 2) ; (if ...) est en pos. terminale 1 ; 1 est en pos. terminale

(* n ; (* ...) est en pos. terminale (fact (- n 1))))))

Déf: un appel terminal c’est un appel de fonction qui est en position terminale

Déf: une fonction récursive est en forme itérative si les appels récursifs sont tous des appels terminaux

(11)

c 2006 Marc Feeley IFT2030 page 149

Forme itérative (5)

fact n’est pas en forme itérative, mais mult-fact l’est:

(define mult-fact (lambda (n m)

(if (= n 0) m

(mult-fact (- n 1) (* n m)))))

Une fonction en forme itérative consomme un espace constant sur la pile tout au long de la récursion

Ce comportement (espace constant) est requis par Scheme

La forme itérative en Scheme peut donc jouer le rôle des boucles dans les langages impératifs

(12)

c 2006 Marc Feeley IFT2030 page 150

Forme itérative (6)

Certains compilateurs de langage impératif (par

exemple gcc et cc de SUN) détectent et optimisent les récursions terminales

int mult_fact(int n, int m) int mult_fact(int n, int m)

{ {

if (n != 0) while (n != 0)

return mult_fact(n-1, n*m); ==> { m = n*m; n = n-1; }

else return m;

return m; }

}

Les bons compilateurs Scheme compilent les fonctions en forme itérative dans le même code qu’une boucle grâce à une transformation similaire

(13)

c 2006 Marc Feeley IFT2030 page 151

Forme itérative (7)

Les traces produites par trace tiennent compte des appels terminaux (l’indentation ne change pas, ce qui indique que le résultat de la fonction sera le résultat de l’appel terminal)

Exemples

avec appel terminal si appel ´etait non-terminal

| > (mult-fact 5 1) | > (mult-fact 5 1)

| > (mult-fact 4 5) | | > (mult-fact 4 5)

| > (mult-fact 3 20) | | | > (mult-fact 3 20)

| > (mult-fact 2 60) | | | | > (mult-fact 2 60)

| > (mult-fact 1 120) | | | | | > (mult-fact 1 120)

| > (mult-fact 0 120) | | | | | | > (mult-fact 0 120)

| 120 | | | | | | 120

| | | | | 120

| | | | 120

| | | 120

| | 120

| 120

(14)

c 2006 Marc Feeley IFT2030 page 152

Forme itérative (8)

Exemple: création d’une liste d’entiers consécutifs

(interv 1 6) => (1 2 3 4 5 6)

Il y a plusieurs façons de faire ce calcul récursivement:

(interv 1 6) = (append (interv 1 5) (list 6))

(interv 1 6) = (cons 1

(interv 2 6))

(interv 1 6) = (append (interv 1 3) (interv 4 6))

(15)

c 2006 Marc Feeley IFT2030 page 153

Forme itérative (9)

Méthode 1 en forme non-itérative

(define interv (lambda (i j)

(if (> i j)

’()

(append (interv i (- j 1)) (list j)))))

Méthode 1 en forme itérative

(define append-interv (lambda (i j lst)

(if (> i j) lst

(append-interv i

(- j 1)

(cons j lst))))) (define interv

(lambda (i j)

(append-interv i j ’())))

(16)

c 2006 Marc Feeley IFT2030 page 154

Forme itérative (10)

Méthode 2 en forme non-itérative

(define interv (lambda (i j)

(if (> i j)

’()

(cons i

(interv (+ i 1) j)))))

Méthode 2 en forme itérative

(define append-rev-interv (lambda (i j lst)

(if (> i j) lst

(append-rev-interv (+ i 1) j

(cons i lst))))) (define interv

(lambda (i j)

(reverse (append-rev-interv i j ’()))))

(17)

c 2006 Marc Feeley IFT2030 page 155

Forme itérative (11)

Méthode 3 en forme non-itérative

(define interv (lambda (i j)

(cond ((> i j)

’())

((= i j) (list i)) (else

(let ((m (quotient (+ i j) 2))) (append (interv i m)

(interv (+ m 1) j)))))))

(18)

c 2006 Marc Feeley IFT2030 page 156

Forme itérative (12)

Méthode 3 partiellement en forme itérative

(define append-interv (lambda (i j lst)

(cond ((> i j) lst)

((= i j)

(cons i lst)) (else

(let ((m (quotient (+ i j) 2))) (append-interv i

m

(append-interv (+ m 1) j

lst))))))) (define interv

(lambda (i j)

(append-interv i j ’())))

(19)

c 2006 Marc Feeley IFT2030 page 157

Fonctions d’ordre supérieur (1)

En Scheme, les fonctions sont des données de première classe

Déf: une donnée est de première classe si les opérations suivantes sont permises

1. Stocker dans des structures de donnée (ou

variables) et transférer d’une structure (ou variable) à une autre

2. Passer en paramètre à des fonctions 3. Retourner comme résultat de fonction

(20)

c 2006 Marc Feeley IFT2030 page 158

Fonctions d’ordre supérieur (2)

Il est avantageux que toutes les données soient de première classe afin que le langage soit uniforme (aucune exception d’utilisation)

En C (contrairement à Pascal), les tableaux ne sont pas de première classe

int t1[10];

int t2[10];

... t1 = t2; ... /* erreur */

En Pascal (contrairement à C), les fonctions ne sont pas de première classe (retour de fonction interdit)

(21)

c 2006 Marc Feeley IFT2030 page 159

Fonctions d’ordre supérieur (3)

Exemple

> (lambda (x) (* x x))

#<procedure #2>

> (define fns (list (lambda (x) (* x x)) (lambda (x) (+ x 1))))

> fns

(#<procedure #3> #<procedure #4>)

> (car fns)

#<procedure #3>

> ((car fns) 10) 100

> ((cadr fns) 10) 11

(22)

c 2006 Marc Feeley IFT2030 page 160

Fonctions d’ordre supérieur (4)

Les fonctions comme données de première classe permettent une programmation plus modulaire:

Algorithmes génériques qu’on peut spécialiser en passant une ou des fonctions (p.e. tri)

• Programme “data driven”: table de fonctions

consultée pour connaître quel traitement faire en fonction du contexte

• “Callback”: fonction qu’on attache à un événement (p.e. cliquer sur un bouton)

(23)

c 2006 Marc Feeley IFT2030 page 161

Fonctions d’O.S. sur les listes (1)

Souvent on a besoin de faire un traitement sur tous les éléments d’une liste

Exemple: élever au carré chaque élément d’une liste pour produire une nouvelle liste:

> (define tous-au-carre (lambda (lst)

(if (null? lst)

’()

(cons (* (car lst) (car lst))

(tous-au-carre (cdr lst))))))

> (tous-au-carre ’(1 2 3)) (1 4 9)

(24)

c 2006 Marc Feeley IFT2030 page 162

Fonctions d’O.S. sur les listes (2)

Et si on cherche plutôt à mettre au cube:

> (define tous-au-cube (lambda (lst)

(if (null? lst)

’()

(cons (* (car lst) (car lst) (car lst))

(tous-au-cube (cdr lst))))))

> (tous-au-cube ’(1 2 3)) (1 8 27)

Les fonctions sont identiques sauf pour le calcul à faire sur chaque élément (cette duplication de code est source d’erreur)

(25)

c 2006 Marc Feeley IFT2030 page 163

Fonctions d’O.S. sur les listes (3)

Une meilleure solution est de concevoir une fonction

map” qui permet d’appliquer un calcul quelconque sur les éléments de la liste

Le “calcul quelconque” sera spécifié par une fonction qui est passée en paramètre à map:

(map (lambda (x) (* x x)) ’(1 2 3))

=> (1 4 9)

(map (lambda (x) (* x x x)) ’(1 2 3))

=> (1 8 27)

(26)

c 2006 Marc Feeley IFT2030 page 164

Fonctions d’O.S. sur les listes (4)

Implantation de map

(define map ; note: pr´ed´efinie (lambda (f lst)

(if (null? lst)

’()

(cons (f (car lst))

(map f (cdr lst))))))

Ainsi map est une fonction générique qu’on peut spécialiser au besoin

(map reverse ’((a b) () (c d e)))

=> ((b a) () (e d c))

map est une fonction polymorphique car ses

paramètres peuvent être de plusieurs formes (liste de nombres/listes/...)

(27)

c 2006 Marc Feeley IFT2030 page 165

Fonctions d’O.S. sur les listes (5)

Autre fonction d’O.S. utile: filtrer les éléments d’une

liste ayant une certaine propriété (fonction pour tester la propriété)

(garder odd? ’(5 8 2 3 1 9)) => (5 3 1 9) (garder (lambda (x) (< x 5)) ’(5 8 2 3 1 9))

=> (2 3 1)

Implantation

(define garder

(lambda (f lst)

(cond ((null? lst)

’())

((f (car lst)) (cons (car lst)

(garder f (cdr lst)))) (else

(garder f (cdr lst))))))

(28)

c 2006 Marc Feeley IFT2030 page 166

Fonctions d’O.S. sur les listes (6)

Exemple: tester si tous les éléments d’une liste possèdent une propriété

(tous odd? ’(9 3 5)) => #t (tous odd? ’(9 3 2 5)) => #f (define tous

(lambda (f lst) (null?

(garder (lambda (x) (not (f x))) lst))))

(29)

c 2006 Marc Feeley IFT2030 page 167

Fonctions d’O.S. sur les listes (7)

Autre fonction d’O.S. utile: trier une liste dans un certain ordre (fonction pour comparer 2 éléments)

(trier < ’(5 8 2 3 1 9)) => (1 2 3 5 8 9) (trier string>? ’("b" "a" "c"))

=> ("c" "b" "a")

(30)

c 2006 Marc Feeley IFT2030 page 168

Fonctions d’O.S. sur les listes (8)

Implantation avec algorithme “Quicksort”:

1. liste vide: déjà triée!

2. sinon: pivot = 1er élément; a = liste des éléments restants < pivot; b = liste des éléments restants ≥

pivot; résultat = a triée + pivot + b triée

(define trier

(lambda (f lst) (if (null? lst)

’()

(let ((p (car lst))) (let ((a (garder

(lambda (x) (f x p)) (cdr lst)))

(b (garder

(lambda (x) (not (f x p))) (cdr lst))))

(append (trier f a)

(cons p (trier f b))))))))

(31)

c 2006 Marc Feeley IFT2030 page 169

Fonctions d’O.S. sur les listes (9)

Autre fonction d’O.S. utile: réduction d’une liste en combinant les éléments (ex. somme ou produit des éléments)

(define somme (lambda (lst)

(if (null? lst) 0

(+ (car lst) (somme (cdr lst)))))) (somme ’(1 2 3 4)) => 10

(define produit (lambda (lst)

(if (null? lst) 1

(* (car lst) (produit (cdr lst)))))) (produit ’(1 2 3 4)) => 24

(32)

c 2006 Marc Feeley IFT2030 page 170

Fonctions d’O.S. sur les listes (10)

Ces fonctions diffèrent sur

1. le résultat pour le cas de base (liste vide): 0 ou 1 2. la fonction de combinaison: + ou *

(foldr + 0 ’(1 2 3 4)) => 10 (foldr * 1 ’(1 2 3 4)) => 24

(33)

c 2006 Marc Feeley IFT2030 page 171

Fonctions d’O.S. sur les listes (11)

Implantation de foldr

(define foldr

(lambda (f base lst) (if (null? lst)

base

(f (car lst)

(foldr f base (cdr lst))))))

Il est à remarquer que foldr combine les éléments à partir de la droite, c’est-à-dire:

(foldr + 0 ’(1 2 3)) = (+ 1 (+ 2 (+ 3 0))) (foldr * 1 ’(1 2 3)) = (* 1 (* 2 (* 3 1)))

(34)

c 2006 Marc Feeley IFT2030 page 172

Fonctions d’O.S. sur les listes (12)

Mais on pourrait combiner à partir de la gauche:

(foldl + 0 ’(1 2 3)) = (+ (+ (+ 0 1) 2) 3) (foldl * 1 ’(1 2 3)) = (* (* (* 1 1) 2) 3)

Implantation de foldl (note: forme itérative)

(define foldl

(lambda (f base lst) (if (null? lst)

base

(foldl f (f base (car lst)) (cdr lst)))))

(35)

c 2006 Marc Feeley IFT2030 page 173

Fonctions d’O.S. sur les listes (13)

foldr et foldl sont omnipotents:

(define somme

(lambda (lst) (foldl + 0 lst)))

(define produit

(lambda (lst) (foldl * 1 lst)))

(define append

(lambda (lst1 lst2) (foldr cons lst2 lst1)))

; (foldr cons ’(3 4) ’(1 2)) = (cons 1

(cons 2

’(3 4)))

(36)

c 2006 Marc Feeley IFT2030 page 174

Fonctions d’O.S. sur les listes (14)

(define reverse

(lambda (lst) (foldl rcons ’() lst))) (define rcons

(lambda (x y) (cons y x)))

;(foldl rcons ’() ’(1 2)) = (rcons (rcons ’() 1) 2)

; = (cons 2 (cons 1 ’()))

(define length (lambda (lst)

(foldl (lambda (x y) (+ x 1)) 0 lst)))

(37)

c 2006 Marc Feeley IFT2030 page 175

Fonctions en résultat (1)

Les fonctions peuvent en plus retourner des fonctions comme résultat

Par exemple, l’opération de dérivation d’une fonction peut être vue comme étant une fonction d’O.S. qui

prend une fonction en paramètre et retourne la fonction qui est sa dérivée

Ainsi, la dérivée de la fonction “sin” c’est la fonction

“cos”

(38)

c 2006 Marc Feeley IFT2030 page 176

Fonctions en résultat (2)

Implantation de la fonction de dérivation par approximation de la pente

(define d

(lambda (f) (lambda (x)

(/ (- (f (+ x .0001)) (f x))

.0001))))

(define c (d sin)) ; d retourne une fonction

(c 0) => .999999998 (c .5) => .877558589 (cos 0) => 1 (cos .5) => .877582561

(39)

c 2006 Marc Feeley IFT2030 page 177

Fonctions en résultat (3)

Déf: soit une fonction f à n paramètres (où n > 1), la forme currifiée de f est une fonction f à un

paramètre (le premier paramètre de f) et qui retourne comme résultat une fonction currifiée traitant les

paramètres restants

Une fonction prenant exactement un paramètre est considérée déjà currifiée

(40)

c 2006 Marc Feeley IFT2030 page 178

Fonctions en résultat (4)

Exemple: addition et multiplication

; non-currifi´ees:

(define add (lambda (x y) (+ x y))) (define mul (lambda (x y) (* x y)))

(add 2 3) => 5 (mul 2 3) => 6

; currifi´ees:

(define addc (lambda (x) (lambda (y) (+ x y)))) (define mulc (lambda (x) (lambda (y) (* x y)))) ((addc 2) 3) => 5 ((mulc 2) 3) => 6

(define f (addc 2)) (define g (mulc 2))

(f 3) => 5 (g 3) => 6

(41)

c 2006 Marc Feeley IFT2030 page 179

Fonctions en résultat (5)

La fonction de composition de fonctions (l’opérateur “o” en mathématique) retourne également une fonction

comme résultat:

(define o (lambda (f g) (lambda (x) (f (g x)))))

f g

(o f g)

((o not odd?) 8) => #t

((o car reverse) ’(1 2 3 4)) => 4

(42)

c 2006 Marc Feeley IFT2030 page 180

Fonctions en résultat (6)

Les fonctions currifiées permettent de facilement

construire des nouvelles fonctions “au besoin” en les composant:

(map (o (addc 1) (mulc 2)) ’(10 20 30))

=> (21 41 61)

(define less-than (lambda (x) (lambda (y) (> x y)))) (garder (o (less-than 5) abs) ’(7 2 -6 -3))

=> (2 -3) (define comp

(lambda (fns)

(foldl o (lambda (x) x) fns)))

((comp (list (addc 1) (mulc 2) sqrt abs)) -9)

=> 7

Références

Documents relatifs

Un conducteur de moto roule avec une vitesse constante v M. Un agent de police voyant l’in- fraction effectue un d´ epart arrˆ et´ e depuis l’´ ecole et lance sa propre moto dans

Support d’une nouvelle méthode pédagogique reposant sur les concepts d’« apprentissage par problèmes » et d’« apprentissage par les pairs », ce livre tente d’amoindrir

On a donc bien démontré qu’en ajoutant les nombres impairs consécutifs à partir de1 on obtient toujours un carré.. L’aire d’un carré est le carré de son côté, et comme

Il y a cependant des problèmes en trigonométrie, et des confusions. Aussi pas mal de difficultés à appliquer le cours pour faire des démonstrations simples. D’autre

★ À l'aide des fonctions produit et extrait, calculez le produit matriciel de deux matrices A et B dans la fonction main. La saisie des deux matrices se fera à l'aide de la

  J’épelle le mot sans modèle..   Je vérifie les

Représenter graphiquement f dans un repère orthogonal, d’unités 5 cm en abscisse et 10 cm en ordonnée.. On prendra 10 comme valeur approchée de

Ainsi, si une in…nité (dénombrable) de personnes viennent assister à une réunion en laissant leur parapluie au vestiaire et repartent en en reprenant un au hasard, la probabilité