• Aucun résultat trouvé

Parseur fonctionnel (1)

N/A
N/A
Protected

Academic year: 2022

Partager "Parseur fonctionnel (1)"

Copied!
39
0
0

Texte intégral

(1)

c 2006 Marc Feeley IFT2030 page 181

Parseur fonctionnel (1)

Un parseur (ou “analyseur syntaxique”) est un

programme qui permet de déterminer si une phrase P fait partie d’un langage L ou pas

Parseur = fonction qui prends une liste de caractères en entrée et qui retourne un Booléen (#t = la liste de caractères est une phrase qui fait partie du langage, sinon #f)

Un parseur va examiner les caractères de gauche à droite

Un stream c’est une liste des caractères qui n’ont pas encore été examinés par le parseur, donc

parseur = stream → Booléen

(2)

c 2006 Marc Feeley IFT2030 page 182

Parseur fonctionnel (2)

Exemple simple: L = { a, b0, b1, ..., b9 }

(define L

(lambda (stream)

(or (and (not (null? stream))

(char=? #\a (car stream)) (null? (cdr stream)))

(and (not (null? stream))

(char=? #\b (car stream)) (not (null? (cdr stream)))

(char-numeric? (cadr stream)) (null? (cddr stream))))))

(L ’(#\a)) => #t (L ’(#\a #\5)) => #f

On aimerait une spécification de plus haut niveau du langage basé sur une grammaire

(3)

c 2006 Marc Feeley IFT2030 page 183

Parseur fonctionnel (3)

Idée: représenter chaque catégorie de la grammaire par une fonction

parseur = stream → (stream | #f)

Si le stream en entrée contient un fragment de phrase qui correspond à la catégorie, le reste de la phrase est retourné, sinon #f

(4)

c 2006 Marc Feeley IFT2030 page 184

Parseur fonctionnel (4)

Les catégories <a> et <b>:

(define a ; r`egle: <a> ::= "a"

(lambda (stream)

(and (not (null? stream))

(char=? #\a (car stream)) (cdr stream))))

(define b ; r`egle: <b> ::= "b"

(lambda (stream)

(and (not (null? stream))

(char=? #\b (car stream)) (cdr stream))))

(a ’(#\a)) => ()

(a ’(#\a #\b #\c)) => (#\b #\c) (a ’(#\b #\a)) => #f

(b ’(#\b #\a)) => (#\a)

(5)

c 2006 Marc Feeley IFT2030 page 185

Parseur fonctionnel (5)

(define c ; r`egle: <c> ::= "0" |...| "9"

(lambda (stream)

(and (not (null? stream))

(char-numeric? (car stream)) (cdr stream))))

(define bc ; r`egle: <bc> ::= <b> <c>

(lambda (stream)

(let ((reste (b stream))) (and reste

(c reste)))))

(define abc ; r`egle: <abc> ::= <a> | <bc>

(lambda (stream) (or (a stream)

(bc stream)))) (define L

(lambda (stream)

(null? (abc stream)))) (L ’(#\b #\4 #\a)) => #f

(6)

c 2006 Marc Feeley IFT2030 page 186

Parseur fonctionnel (6)

Amélioration: faire abstraction des patrons

Constructeur de parseur = fonction qui retourne un parseur

(define char

(lambda (test)

(lambda (stream)

(and (not (null? stream)) (test (car stream)) (cdr stream)))))

(define char=

(lambda (c)

(char (lambda (x) (char=? x c))))) (define a (char= #\a))

(define b (char= #\b))

(define c (char char-numeric?))

(7)

c 2006 Marc Feeley IFT2030 page 187

Parseur fonctionnel (7)

(define seq

(lambda (p1 p2)

(lambda (stream)

(let ((reste (p1 stream))) (and reste

(p2 reste)))))) (define choix

(lambda (p1 p2)

(lambda (stream) (or (p1 stream)

(p2 stream))))) (define fin null?)

(define bc (seq b c))

(define abc (choix a bc)) (define L (seq abc fin))

(L ’(#\b #\4)) = ((seq abc fin) ’(#\b #\4))

= ... = #t

(8)

c 2006 Marc Feeley IFT2030 page 188

Parseur fonctionnel (8)

La spécification du langage est maintenant très proche de la grammaire:

; librairie de construction de parseur:

(define char (lambda (test) ...)) (define char= (lambda (c) ...))

(define seq (lambda (p1 p2) ...)) (define choix (lambda (p1 p2) ...)) (define fin null?)

; sp´ecification du langage L:

(define L

(seq (choix (char= #\a)

(seq (char= #\b)

(char char-numeric?))) fin))

(9)

c 2006 Marc Feeley IFT2030 page 189

Parseur fonctionnel (9)

Extension pour exprimer l’itération?

(define vide ; fragment vide (lambda (stream)

stream))

(define iter+ ; it´eration non-nulle (lambda (p)

(seq p (iter* p))))

(define iter* ; it´eration possiblement nulle (lambda (p)

(lambda (stream)

((choix (iter+ p) vide) stream))))

(define L

(seq (iter+ (char char-numeric?)) (seq (char= #\.)

(seq (iter* (char char-numeric?)) fin))))

(10)

c 2006 Marc Feeley IFT2030 page 190

Parseur fonctionnel (10)

Construction automatique de l’ASA

Idée: changer la signature des parseurs

parseur = stream → ((ASA × stream) | #f)

c’est-à-dire qu’un parseur retourne soit #f ou bien une paire qui contient l’ASA correspondant au fragment de phrase examiné par le parseur et le reste de la phrase

(define res cons) ; constructeur (define res-ASA car) ; partie ASA

(define res-stream cdr) ; partie stream

(11)

c 2006 Marc Feeley IFT2030 page 191

Parseur fonctionnel (11)

(define char

(lambda (test)

(lambda (stream)

(and (not (null? stream)) (test (car stream))

(res (car stream) (cdr stream)))))) (define seq

(lambda (p1 p2)

(lambda (stream)

(let ((r1 (p1 stream))) (and r1

(let ((r2 (p2 (res-stream r1)))) (and r2

(res (cons (res-ASA r1) (res-ASA r2))

(res-stream r2))))))))) (define vide (lambda (stream) (res ’() stream))) (define fin (lambda (stream)

(and (null? stream)

(res ’() stream))))

(12)

c 2006 Marc Feeley IFT2030 page 192

Parseur fonctionnel (12)

(define L

(seq (iter+ (char char-numeric?)) (seq (char= #\.)

(seq (iter* (char char-numeric?)) fin))))

(res-ASA (L ’(#\1 #\2 #\. #\3 #\4)))

=> ((#\1 #\2) #\. (#\3 #\4))

car cdr

car cdr

()

car cdr

#\2

car cdr

()

car cdr car cdr

()

car cdr

#\.

#\1

#\3

#\4

(13)

c 2006 Marc Feeley IFT2030 page 193

Continuations (1)

Déf: la continuation d’une fonction f c’est une fonction k passée en paramètre à f qui indique quel calcul il faut faire avec “le(s) résultat(s)” de la fonction f

Exemple: fonction qui additionne 2 nombres

(define add

(lambda (x y cont) (cont (+ x y))))

(add 2 3 (lambda (r) (* r r))) => 25

(14)

c 2006 Marc Feeley IFT2030 page 194

Continuations (2)

Exemple pratique: “retourner” plusieurs résultats

(define racines ; racines de axˆ2+bx+c=0 (lambda (a b c cont)

(let ((d (sqrt (- (* b b) (* 4 a c))))) (cont (/ (+ (- b) d) (* 2 a))

(/ (- (- b) d) (* 2 a))))))

(racines 1 0 -1 (lambda (r1 r2) (* r1 r2)))

=> -1

Dans cet exemple l’utilisation d’une continuation évite la création d’une liste (pour retourner les 2 racines) et

c’est plus élégant que:

(let ((r (racines 1 0 -1))) ; version ``liste’’

(let ((r1 (car r)) (r2 (cadr r))) (* r1 r2)))

(15)

c 2006 Marc Feeley IFT2030 page 195

Continuations (3)

Exemple: partitionner une liste en 2 suivant une

certaine propriété des éléments (fonction qui retourne un Booléen), il y a 2 résultats:

1. éléments pour lesquels la fonction donne #t 2. éléments pour lesquels la fonction donne #f

(define partitionner (lambda (f lst cont)

(if (null? lst)

(cont ’() ’()) (partitionner

f

(cdr lst)

(lambda (a b)

(if (f (car lst))

(cont (cons (car lst) a) b)

(cont a (cons (car lst) b))))))))

(16)

c 2006 Marc Feeley IFT2030 page 196

Continuations (4)

(define trier ; implantation de ``Quicksort’’

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

’()

(let ((p (car lst))) (partitionner

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

(lambda (a b)

(append (trier f a)

(cons p (trier f b))))))))) (trier < ’(5 8 2 3 1 9)) => (1 2 3 5 8 9)

(17)

c 2006 Marc Feeley IFT2030 page 197

Continuations (5)

À l’aide des continuations, il est possible de transformer n’importe quelle fonction en une fonction en forme

itérative

L’idée c’est d’ajouter une continuation à toute fonction qui est utilisée dans un appel non-terminal, afin de

transformer cet appel en un appel terminal (la

continuation représente le calcul qui consomme le résultat de l’appel)

(18)

c 2006 Marc Feeley IFT2030 page 198

Continuations (6)

Exemple simple: calcul de la factorielle

(define fact (lambda (n)

(if (= n 0) 1

(* n (fact (- n 1))))))

; transformation en forme it´erative:

(define fact-fi

(lambda (n cont) (if (= n 0)

(cont 1)

(fact-fi (- n 1)

(lambda (r)

(cont (* n r))))))) (define fact

(lambda (n)

(fact-fi n (lambda (r) r))))

(19)

c 2006 Marc Feeley IFT2030 page 199

Continuations (7)

> (define fact-fi (lambda (n cont)

(if (= n 0) (cont 1)

(fact-fi (- n 1)

(lambda (r)

(cont (* n r)))))))

> (define fact (lambda (n) (fact-fi n (lambda (r) r))))

> (trace fact fact-fi)

> (fact 5)

| > (fact 5)

| > (fact-fi 5 ’#<procedure #2>)

| > (fact-fi 4 ’#<procedure #3>)

| > (fact-fi 3 ’#<procedure #4>)

| > (fact-fi 2 ’#<procedure #5>)

| > (fact-fi 1 ’#<procedure #6>)

| > (fact-fi 0 ’#<procedure #7>)

| 120 120

; Avec:

; #<procedure #2> = (lambda (r) r)

; #<procedure #3> = (lambda (r) (’#<procedure #2> (* 5 r)))

; #<procedure #4> = (lambda (r) (’#<procedure #3> (* 4 r)))

; #<procedure #5> = (lambda (r) (’#<procedure #4> (* 3 r)))

; #<procedure #6> = (lambda (r) (’#<procedure #5> (* 2 r)))

; #<procedure #7> = (lambda (r) (’#<procedure #6> (* 1 r)))

Les fermetures créées pour la continuation de fact-fi jouent le même rôle que la pile d’exécution

(20)

c 2006 Marc Feeley IFT2030 page 200

Continuations (8)

Autre exemple: append

(define append

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

lst2

(cons (car lst1)

(append (cdr lst1) lst2)))))

; transformation en forme it´erative:

(define append-fi

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

(cont lst2)

(append-fi (cdr lst1) lst2

(lambda (r)

(cont (cons (car lst1) r))))))) (define append

(lambda (lst1 lst2)

(append-fi lst1 lst2 (lambda (r) r))))

(21)

c 2006 Marc Feeley IFT2030 page 201

Continuations (9)

> (trace append append-fi)

> (append ’(1 2 3) ’(4 5))

| > (append ’(1 2 3) ’(4 5))

| > (append-fi ’(1 2 3) ’(4 5) ’#<procedure #2>)

| > (append-fi ’(2 3) ’(4 5) ’#<procedure #3>)

| > (append-fi ’(3) ’(4 5) ’#<procedure #4>)

| > (append-fi ’() ’(4 5) ’#<procedure #5>)

| (1 2 3 4 5) (1 2 3 4 5)

; Avec:

; #<procedure #2> = (lambda (r) r)

; #<procedure #3> = (lambda (r) (’#<procedure #2> (cons 1 r)))

; #<procedure #4> = (lambda (r) (’#<procedure #3> (cons 2 r)))

; #<procedure #5> = (lambda (r) (’#<procedure #4> (cons 3 r)))

(22)

c 2006 Marc Feeley IFT2030 page 202

Continuations (10)

Les continuations sont aussi utiles pour les algorithmes génériques de fouille

Un arbre binaire peut être représenté à l’aide de listes:

noeud = (val gauche droite) et arbre vide = ()

Donc (4 (3 () ()) (-1 (-8 () ()) ())) représente 4

3 -1

-8

(23)

c 2006 Marc Feeley IFT2030 page 203

Continuations (11)

Voici une fonction de fouille par parcours infixe de l’arbre

(define fouille-infixe

(lambda (arbre visite fin) ; 2 continuations (if (null? arbre)

(fin)

(fouille-infixe (cadr arbre) visite

(lambda ()

(visite (car arbre) (lambda ()

(fouille-infixe (caddr arbre) visite

fin))))))))

(24)

c 2006 Marc Feeley IFT2030 page 204

Continuations (12)

Utilisation 1: trouver le premier nombre négatif

(fouille-infixe

’(4 (3 () ()) (-1 (-8 () ()) ())) (lambda (x cont)

(if (< x 0) x (cont))) (lambda ()

#f))

=> -8

4

3 -1

-8

(25)

c 2006 Marc Feeley IFT2030 page 205

Continuations (13)

Utilisation 2: convertir l’arbre en liste

(fouille-infixe

’(4 (3 () ()) (-1 (-8 () ()) ())) (lambda (x cont)

(cons x (cont))) (lambda ()

’()))

=> (3 4 -8 -1)

4

3 -1

-8

(26)

c 2006 Marc Feeley IFT2030 page 206

Continuations (14)

Utilisation 3: liste des nombres impairs

(fouille-infixe

’(4 (3 () ()) (-1 (-8 () ()) ())) (lambda (x cont)

(if (odd? x) (cons x (cont)) (cont))) (lambda ()

’()))

=> (3 -1)

4

3 -1

-8

(27)

c 2006 Marc Feeley IFT2030 page 207

Tests de type (1)

Il existe des fonctions primitives pour tester

dynamiquement le type d’une donnée (ces fonctions sont applicables sur n’importe quel type de donnée et retournent #f ou #t)

(null? x) => x est la liste vide?

(pair? x) => x est une liste non-vide?

(char? x) => x est un caractère?

(number? x) => x est un nombre?

(string? x) => x est une chaîne de caractères?

(symbol? x) => x est un symbole?

(boolean? x) => x est un Booléen (#f ou #t)?

(procedure? x) => x est une procédure?

(28)

c 2006 Marc Feeley IFT2030 page 208

Tests de type (2)

Exemple

(define f

(lambda (nom)

(string-append "allo "

(if (symbol? nom)

(symbol->string nom) nom))))

(f ’marc) => "allo marc"

(f "marc") => "allo marc"

(29)

c 2006 Marc Feeley IFT2030 page 209

Affectation et effets de bord (1)

Scheme n’est pas un langage purement fonctionnel car il possède l’affectation (et des fonctions

d’entrée/sortie)

Le style impératif est donc possible

Afin de traiter l’affectation correctement chaque variable dans l’environnement est en fait une cellule dont le

contenu peut être modifié par affectation

L’affectation se fait avec la forme spéciale set!:

• (set! hvari hexpri) évalue hexpri et stocke le résultat dans la cellule de la variable hvari

• set! retourne une valeur indéfinie

(30)

c 2006 Marc Feeley IFT2030 page 210

Affectation et effets de bord (2)

Exemple

> (define x 1)

> (set! x (+ x 1))

> x 2

> (set! x "allo")

> x

"allo"

(31)

c 2006 Marc Feeley IFT2030 page 211

Affectation et effets de bord (3)

Scheme possède également la forme spéciale begin qui exprime un séquencement d’évaluations (utile pour forcer l’ordre d’exécution des effets de bord)

• (begin hexpr1i ... hexprNi) évalue chaque sous-expression de gauche à droite

• la valeur de hexprNi est retournée

(32)

c 2006 Marc Feeley IFT2030 page 212

Affectation et effets de bord (4)

Exemple

> (begin

(display "hello world!") (newline)

(+ 2 3)) hello world!

5

> (define boucle (lambda ()

(begin

(display "entrer n: ") (let ((x (read)))

(if (number? x) (begin

(write (sqrt x)) (newline)

(boucle)))))))

> (boucle) entrer n: 10

3.1622776601683795 entrer n: 4

2

entrer n: fin

(33)

c 2006 Marc Feeley IFT2030 page 213

Affectation et effets de bord (5)

Il y a une interaction interessante entre les fermetures et les affectations

Chaque fermeture mémorise l’environnement de la lambda-expression correspondante incluant les cellules associées:

> (define accumuler (let ((n 0))

(lambda (x)

(begin (set! n (+ n x)) n))))

> (accumuler 5) 5

> (accumuler 5) 10

Dans cet exemple, on a encapsulé la variable n

(34)

c 2006 Marc Feeley IFT2030 page 214

Encapsulation

Déf: une variable ou fonction est encapsulée si elle est accessible seulement aux parties du programme qui

ont une raison légitime d’y accéder

L’encapsulation permet d’accroître la modularité (car dépendances claires) et robustesse (on peut garantir des invariants par examination locale du code: par

exemple, n toujours un nombre)

L’encapsulation est une approche utile en

programmation orientée-objet (les données sont encapsulées dans la définition de classe)

(35)

c 2006 Marc Feeley IFT2030 page 215

Encapsulation: Exemple

1. (define creer-compte

2. (lambda (solde)

3. (lambda (msg)

4. (cond ((equal? msg ’depot)

5. (lambda (n)

6. (if (< n 0)

7. (error "d´epot erron´e")

8. (set! solde (+ solde n)))))

9. ((equal? msg ’retrait)

10. (lambda (n)

11. (if (or (< n 0) (> n solde))

12. (error "retrait erron´e")

13. (set! solde (- solde n)))))

14. ((equal? msg ’lire-solde)

15. (lambda () solde))

16. (else

17. (error "op´eration erron´ee"))))))

18.

19. (define c1 (creer-compte 100))

20.

21. (define c2 (creer-compte 0))

22.

23. ((c1 ’retrait) 30)

24.

25. ((c2 ’depot) 15)

26.

27. ((c1 ’lire-solde)) => 70

28. ((c2 ’lire-solde)) => 15

29.

30. ((c1 ’retrait) 80) => *** ERROR -- retrait erron´e

(36)

c 2006 Marc Feeley IFT2030 page 216

Encapsulation et Modules (1)

L’encapsulation sert aussi à créer des modules qui cachent leur implantation des clients

En Scheme: affectation + définitions locales

Exemple: module de génération de nombres

pseudo-aléatoires suivant certaines distributions

fonction exportée (loi-uniforme a b)

fonction exportée (loi-exponentielle m)

fonction interne (entier-aleatoire)

(37)

c 2006 Marc Feeley IFT2030 page 217

Encapsulation et Modules (2)

1. (define loi-uniforme #f)

2. (define loi-exponentielle #f)

3.

4. (let () ; fronti`ere d’encapsulation

5.

6. (define graine 1673) ; ´etat du g´en´erateur

7. (define k1 3581) ; constantes du g´en´erateur congruentiel

8. (define k2 12751)

9. (define k3 131072)

10.

11. (define entier-aleatoire

12. (lambda ()

13. (begin

14. (set! graine (modulo (+ (* graine k1) k2) k3))

15. graine)))

16.

17. (define uniforme

18. (lambda (a b) ; a et b sont les bornes de l’intervalle

19. (+ a (* (- b a) (/ (entier-aleatoire) (- k3 1))))))

20.

21. (define exponentielle

22. (lambda (m) ; nombre entre 0 et +inf, m est la moyenne

23. (- (* m (log (uniforme 0 1))))))

24.

25. (begin

26. (set! loi-uniforme uniforme)

27. (set! loi-exponentielle exponentielle)))

(38)

c 2006 Marc Feeley IFT2030 page 218

Mutation des Données (1)

Scheme offre aussi des fonctions de mutation pour modifier le contenu des données structurées

paires: (set-car! p d) et (set-cdr! p d)

chaînes: (string-set! s i c)

vecteurs: (vector-set! v i d)

(39)

c 2006 Marc Feeley IFT2030 page 219

Mutation des Données (2)

Exemple: renverser une liste destructivement

(define reverse!

(lambda (lst)

(define rev! ; d´efinition ``locale’’

(lambda (lst res) (if (null? lst)

res

(let ((temp (cdr lst))) (begin

(set-cdr! lst res) (rev! temp lst)))))) (rev! lst ’())))

(define x (list 3 4 5))

(define y (cons 1 (cons 2 x))) (reverse! y) => (5 4 3 2 1) x => (3 2 1)

y => (1)

Références

Documents relatifs

Mais, lors de la mitose (3) nom donné à la division des cellules somatiques, on constate que les chromosomes sont identiques deux à deux (ces cellules sont

Il peut être parfois traduit mais il ne donne de toutes façons pas de polypeptide fonctionnel : non seulement celui-ci peut posséder quelques acides

chez la levure , un caractère défavorable sur milieu minimum peut être utilisé pour procéder à un enrichissement en mutants compensables auxotrophes.. repérage

Par contre, lorsque deux mutants haploïdes donnent un diploïde dont le phénotype est celui de la souche de référence, on en conclut que leurs mutations n’affectent

8-10 : la méthode .extend() ajoute en bout de liste tous les éléments de la liste passée en argument ; liste a alors trois éléments?. Dans les exemples qui suivent, on crée de

Barbiche Oreilles en pavillon Moustaches (vibrisses). Crête Barbillons

Présenter dans un tableau les dié- rentes expressions de f (x) et les intervalles dans lesquels elles sont valides.. Retrouver le tableau précédent en utilisant

Présenter dans un tableau les dié- rentes expressions de f (x) et les intervalles dans lesquels elles sont valides.. Retrouver le tableau précédent en utilisant