Top Posters
Since Sunday
A free membership is required to access uploaded content. Login or Register.

Programmation fonctionnelle et logique.docx

Uploaded: 6 years ago
Contributor: redsmile
Category: Data Structures
Type: Other
Rating: N/A
Helpful
Unhelpful
Filename:   Programmation fonctionnelle et logique.docx (557.76 kB)
Page Count: 35
Credit Cost: 2
Views: 134
Last Download: N/A
Transcript
Cours de Programmation fonctionnelle et logique Chapitre 1 : Introduction générale Lisp : c'est un langage de programmation inventé au MIT par John MAC Carty et Coll (1960), c'est aussi ancien que le fortran. Il existe 3 grandes familles: MAC LISP (MIT) Le Lisp de Franz Lisp INTER LISP (Xerox: Pala Alto) Commun Lisp (futur standard MIT) à donner Scheme On travaillera sous: Dr Scheme Scheme du MIT Auteur : Steele, Abelson, Sussman Il existe aussi Open Scheme (MAC) Différence entre Scheme et les autres Lisp Portée statique (lexicale) des variables (liaisons lexicale) en opposition à dynamique Notion d'environnement On peut utiliser les programmes (comme données) en entrée et en sortie à d'autres programmes, grâce au lambda calcul (-calcul) Classification rapide des langages de programmation : Langages fonctionnels ( Lisp, Scheme : non typé, ML, CAML: très fortement typé) Pas d'effet de bord sauf pour les E/S On y programme essentiellement par opposition de fonction (Un programme = un ensemble de fonctions, sans fonction principale) les informations circulant entre les programmes par l'intermédiaire des paramètres des fonctions. Langages applicatifs (?Cobol, SQL) Programmation fonctionnelle sans variable Langages impératifs On programme avec les instructions qui agissent par effet de bord en modifiant le contenu de la mémoire. Langages logiques (relationnels) Prolog, Datalog Langages orientés objets (Small talk, ……, C++, Java) Remarque : 2 grandes approche dans la programmation Une approche "impérative" (opérationnelle) totalement déterministe, où l'on décrit à la machine, exactement ce qu'elle doit faire (un programme = suite d'instruction à exécuter par la machine) Une approche déclarative, totalement non déterministe : on décrit à la machine ce que l'on veut qu'elle calcule (c'est à elle de trouver l'algo) des langages s'en approche Prolog, CAML, Lisp Les langages impératifs au départ été voué au calcul numérique opposé au calcul symbolique. Chapitre 2 : Principale caractéristique de Lisp / Scheme Lisp Pur: Un noyau de langage très réduit existe dans lequel presque tout lisp est définissable ( sauf pour les E/S) Lisp contient le -calcul (un système logique qui permet de représenter simplement, seulement 3 sortes de termes, tout ce qui est calculable par la machine) Boot strap 2889255207000 654685508000 111188527305Lisp pur 00Lisp pur 8375652540Couche supplémentaire 00Couche supplémentaire 92900546990Couche supplémentaire 00Couche supplémentaire Modules La programmation modulaire est tout à fait naturelle puisqu'un programme est un ensemble de fonctions: 1460588900; commentaire ; … F1 00; commentaire ; … F1 1569085111125module 00module 1460539370; commentaire ; … F2 00; commentaire ; … F2 156908561595module 00module Récursion: La programmation récursive est tout à fait naturelle en Lisp Typage: Pas de type en Lisp: Il y a un contrôle dynamique du typage, c'est à dire lors de l'exécution des programmes Il existe quelques test de type qui permettent de programmer le typage Les listes sont hétérogènes Mémoire: De même, il y a une allocation dynamique de la mémoire, pas de déclaration préalable à faire, fixant la taille des structures de données utilisées : on donne des listes de longueur arbitraire Les systèmes Lisp sont interactifs : Une fois sous Unix ( taper Scheme), le système demande à l'utilisateur de lui taper une EXPRESSION qu'il va se charger d'EVALUER, une fois la valeur de l'expression retournée, le système (l'interpréteur et/ou le compilateur + machine exécutant le code) en redemande une autre, jusqu'à ce que l'utilisateur lui demande d'arrêter (^D) Noter que la valeur d'une "constante" c'est à dire une donnée basique comme un entier, un booléen est cette constante Un tel déroulement (une SESSION) se déroule de la manière suivante : On entre dans une boucle : "Read - eval - print" c'est à dire : "lecture - évaluation - impression" ou encore : " boucle top level" dont on ne sort qu'en interrompant tout le processus lié au système. Exemple: $ scheme >(+ 2 3) ; ceci est un commentaire ; le prompt Scheme "" s'affiche ; l'utilisateur lui tape une expression à évaluer 5 ; réponse de l'interprète : évaluation de l'expression (+ 2(* 3 5)) ; la notation est préfixe parenthésée 17 (eq? (< 3 2) #t) ; Sous le Scheme du MIT #t #! true #f ; écriture abrégée de #! false > #t ; écriture abrégée de #! true #t > 5 ; la valeur d'une constante est cette constante 5 ; constante = données de base comme dans les autres langages de ; programmation > '(1 2 3) ; si une liste précédée du signe '(quote) l'interpréteur la répète (1 2 3) ; elle n'est pas évalué (à l'intérieur) (1.(2 3)) ; le . permet de construire des listes (ne marche pas sous scheme) (1 2 3) > (cons 1 '(2 3)) ; cons fait la même chose que le . (1 2 3) ; . et cons sont des constructeur de liste > (car '( 1 2 3)) ; car et cdr sont des destructeur de listes 1 > (cdr '(1 2 3)) (2 3) > (reverse '(1 2 3)) (3 2 1) > (reverse '(a b a)) (a b a) > (reverse '((1 2) 3 4)) (4 3 (1 2)) > (equal? (cons 3 '(2 1)) (reverse '(1 2 3))) ; equal? compare deux liste #t (if (equal? () #!null) "liste-vide" (liste non vide)) liste-vide ; ne marche pas sous MzScheme ^D ; on sort de Sheme $ ;on est sous Unix > cons ; cons est une fonction prédéfinie # > #f ; #f est une constante prédéfinie #f x ; une variable non définie = non liée à une valeur dans Unbounded variable x ; l'environnement Error! Level 2: Error ^G (rtn) ; pour retourner au Top Level > (define x (+ 1 1)) ; une définition de variable simple x > x 2 > (+ x 3) 5 > x ; x a garder sa valeur 2 2 > (define (f x y)(+ x (* x y))) ; une définition de fonction ; f est le nom de la fonction ; x et y sont les paramètres de la fonction ; (+ x (* x y))est le corps de la fonction et ne ; comporte pas d'autres variables en dehors des ; paramètres de f f > f # (pp f) ; pp = pretty printer (named-lambda (f x y) ; ne marche pas sous MzScheme (+ x (* x y))) ;No value > (f 5 3) ; appel de la fonction sur des arguments 20 > x ; x a garder sa valeur 2 2 > (define x (+ x 3)) ; on redéfinit x x > x ; on voit que la valeur de x a maintenant changée 5 > (define (fact n) ; définition de fonction récursive : la fonction factorielle (if (= n 0) ; 0!=1 et n! = n(n-1)! Si n>0 1 (* n (fact (- n 1))))) fact > (fact 100) 93326215443944152681699238856266700490715968264381621468592963895217599993229915608941463976156518286253697920827223758251185210916864000000000000000000000000 > (define (somme-liste l) ; On calcul la somme des éléments d'une liste (if (null? l) ; d'entiers 0 (+ (car l) (somme-liste (cdr l))))) somme-liste > (somme-liste '(1 2 3 4 5)) 15 (sys : oblist) ; ne marche pas sous Scheme (……) ; retourne la (très longue) liste des variables liées dans l'environnement ^D ; courant (dont les prédéfinies) $ L'environnement est une liste de liaisons: Tout ce qui sert habituellement de déclaration dans les langages non itératifs et qu'on retrouve en tête des programmes se retrouve ici défini au fur et à mesure des besoins de l'utilisateur d'où la nécessité d'un tel environnement continuellement mis à jour. Il y a une gestion dynamique des valeurs des variables et donc de sémantique dynamique des programmes. Chapitre 3 : Syntaxe et structures de données Lisp / Scheme Définition des S-exp : l'arbre binaire Dans Lisp on a essentiellement une seule structure de donnée non atomique : l'arbre binaire encore appelé S-exp Aux feuilles de ces arbres il y a des valeurs atomiques comme: Des nombres Des booléens Des chaînes de caractères Des symboles Etc … Les autres types de variables non atomiques sont: Les vecteurs Les tableaux Les pointeurs On a la grammaire suivante: 1111885-190500 Sexp = constante S-expressions atomiques = ATOMES Symbole (littéraux dans le 2eme cas) (Sexp . Sexp) S-expressions non atomiques Constante = #! null ; S-exp vide (autre écriture : (), nil) #! truc | #! false ; booléens (autre écriture : #t, t et #f) suite de chiffres (et de caractères éventuellement) ; nombres #! c ; caractère c "suite de caractères" ; chaînes de caractères Symbole = identificateur ; suite de caractères ne commencant pas par un chiffre ; quelques caractères sont réservés Remarque : Dans une bibliothèque à chargée à chaque fois on a (define nil ()) Il faut, pour charger la bibliothèque faire load "nom_fichier.scm" Vérifier si l'on a un fichier init.scm ? Note : Le caractère spécial : ' utilisé pour empêcher l'évaluation de certaines expressions ne figure pas dans cette grammaire, c'est une abréviation pour une fonction prédéfinie (cf section VI) Sera pris comme commentaire dans un programme tout ce qui est sur la même ligne derrière un ;. Dans cette syntaxe la représentation linéaire des S-exp est utilise sur machine, mais on peut avoir besoin d'une représentation arborescente des S-exp 111188524892000TS-exp = Atome . 1294765151130S-exp 00S-exp 837565151130S-exp 00S-exp 13862055969000 Exemples de S-exp : S-exp atomiques: 257492559055constantes 00constantes 24834855905500 2, 3, très grands entiers …, 3.14, … (), #t, #f,… 24834851841500 +, cons, if, define, x, it, lisp symboles 248348513208000 #!x, "chaine", constantes constantes 202628591440 . 00 . S-exp non atomiques: (2.3) représenté par l'arbre: 23006051282703 003 17519651282702 002 2209165368300019348453683000 257492512065 . 00 . (1.(2.3)) représenté par l'arbre : 2483485711200027578057112000 230060519051 001 28492451905 . 00 . 275780524130003032125241300031235651155703 003 25749251155702 002 (1.(2.(3.() ))) représenté par l'arbre : 230060560325 . 00 . 2209165996950024834859969500 2026285469901 001 257492546990 . 00 . 2483485711200027578057112000 230060519052 002 28492451905 . 00 . 3123565115570( ) 00( ) 275780524130003032125241300025749251155703 003 Le dernier exemple est ce que l'on appelle une liste propre en anglais p-list, et on peut l'écrire plus simplement sous la forme (1 2 3) Autre exemple de liste propre : (+.(2.(3.())) (+ 2 3) représenter par: 230060565405 . 00 . 2209165996950024834859969500 202628546990+ 00+ 257492546990 . 00 . 2483485711200027578057112000 230060519052 002 28492451905 . 00 . 3123565115570( ) 00( ) 275780524130003032125241300025749251155703 003 On communique avec l'interpréteur au moyen des listes (des S-exp) et pas avec les arbres, mais une simplification d'écriture est indispensable : c'est la notation de liste. Règle pour passer de la représentation linéaire des S-exp, à la notation de liste : Si e est une S-exp quelconque alors on remplace dans e tous les (s1 . (s2) ) par (s1 s2) (s1 . ( ) ) par (s1) Si il ne reste plus de point . dans la notation de liste d'une S-exp on dit alors que c'est une liste propre (liste) Exemples : 3215005128270 . 00 . Représentation linéaire générale Arbre binaire Notation liste 33978851441450034893252355852 002 31235651441450029406852355851 001 3215005601345 . 00 . (1 . 2) (1 . 2) 3215005683895 . 00 . 3397885135255003489325226695 . 00 . 3763645501015( ) 00( ) 32150055010152 002 33978854095750036722054095750031235651352550029406852266951 001 (1. (2. () )) (1 2) 3215005697230 . 00 . 39465254229104 004 33978854229103 003 30321254229102 002 24834854229101 001 29406855715000339788557150003580765331470003672205148590 . 00 . 3855085331470002940685331470002757805148590 . 00 . 266636533147000(1. 2) . (3 . 4) ( (1 . 2) 3 . 4 ) 40379651076325( ) 00( ) 358076510763254 004 4037965984885003855085802005 . 00 . 37636459848850033978858020053 003 26663658020052 002 3123565802005( ) 00( ) 3946525527685( ) 00( ) 2940685527685 . 00 . 3580765527685 . 00 . 34893257105650028492457105650037636457105650031235657105650039465254362450028492454362450023920455276851 001 3672205436245002574925436245003763645253365 . 00 . 2666365253365 . 00 . 3397885704850028492457048500( (1. (2. ( ) )) . ((3. (4( ) )) . ( ) ) ) ( (1 2) (3 4) ) Remarque : 92900597790 . 00 . On voit que pour les listes propre on a toujours un schéma du type suivant: 2300605144145Toute les feuilles droite sont Toujours ( ) 00Toute les feuilles droite sont Toujours ( ) 8375655080000120332550800 . 00 . 11118852857500 138620514224000 111188538100014776453810 . 00 . 13862051174750016605259525000 166052526035( ) 00( ) Exercice : On considère les listes suivantes, les écrire sous formes de S-exp et sous forme d'arbre: (1 2 3) ((1) 2 3) (1 (2) 3) (1 2 (3)) ((1 2) 3) (1 (2 3)) ((1) 2 (3)) ((1 2 3)) (1. (2. ( 3. ( ) )) 92900522225 . 00 . 6546851358901 001 120332544450 . 00 . 837565444500011118852857500 138620514224000 929005889002 002 111188538100014776453810 . 00 . 13862051174750016605259525000 166052541910( ) 00( ) 1203325419103 003 746125108585 . 00 . ( (1. ( ) ) . (2. ( 3. ( ) )) 9290051162050047180511620500 28892546990 . 00 . 120332544450 . 00 . 47180569215001974856921500138620514224000 4718050( ) 00( ) 1460501 001 929005889002 002 111188538100014776453810 . 00 . 13862051174750016605259525000 166052541910( ) 00( ) 1203325419103 003 929005111125 . 00 . (1 . ( (2. ( ) ) . (3 . ( ) ) ) ) 83756514097000111188514097000 654685717551 001 120332571755 . 00 . 9290052476500837565116205 . 00 . 1660525116205 . 00 . 13862052476500 74612513906500102044513906500156908513906500184340513906500 654685698502 002 102044569850( ) 00( ) 184340569850( ) 00( ) 1477645698503 003 (1. ( 2. (3. ( ) ) . ( ) ) ) 92900522225 . 00 . 6546851358901 001 120332544450 . 00 . 837565444500011118852857500 138620514224000 929005889002 002 111188538100014776453810 . 00 . 1203325141605 . 00 . 13862051174750016605259525000 166052541910( ) 00( ) 138620594615( ) 00( ) 929005946153 003 13862053175001111885317500 1203325161290 . 00 . ( (1. (2. ( ) ) ) . (3 . ( ) ) ) 13862052476500156908599695 . 00 . 10204452476500837565116205 . 00 . 1751965121920001477645121920001020445121920 . 00 . 74612513906500102044513906500 175196552705( ) 00( ) 1386205527053 003 563245144145 1 00 1 1203325749300010204457493000 92900557152 002 12033255715( ) 00( ) ( 1 . ( (2 . (3 . ( ) ) ) . ( ) ) 92900522225 . 00 . 6546851358901 001 8375654445000111188544450001203325135890 . 00 . 1386205247650010204452476500837565116205 . 00 . 156908519685( ) 00( ) 1020445121920 . 00 . 74612513906500102044513906500 563245144145 2 00 2 1203325749300010204457493000 92900557153 003 12033255715( ) 00( ) ( (1 . ( ) ) . (2 . ( (3 . ( ) ) . ( ) ) ) ) 74612546990 . 00 . 47180569215009290056921500 2889250 . 00 . 120332544450 . 00 . 4718051136650019748511366500138620514224000 56324544450( ) 00( ) 14605444501 001 929005889002 002 111188538100014776453810 . 00 . 1203325141605 . 00 . 13862051174750016605259525000 166052541910( ) 00( ) 138620594615( ) 00( ) 929005946153 003 13862053175001111885317500 ( (1 . (2 . (3. ( ) ) ) ) . ( ) ) 1386205635 . 00 . 1569085228600011118852286000 175196545085( ) 00( ) 92900522225 . 00 . 6546851358901 001 120332544450 . 00 . 837565444500011118852857500 138620514224000 929005889002 002 111188538100014776453810 . 00 . 13862051174750016605259525000 166052541910( ) 00( ) 1203325419103 003 Cours de Programmation fonctionnelle et logique 26.04.2000 Note: Avec DrScheme il est préférable d'utiliser MzScheme Chapitre 3 : Syntaxe et structures de données Lisp / Scheme (suite) Exemple: >'(1 2 3) (1 2 3) (quote 1 2 3) ; ' ou ` sont des macros caractères c'est à dire des caractères utilisés comme (1 2 3) ; abréviation pour ces fonctions prédéfinies ; combinaison du ` et de la , (ne marche pas sous MzScheme) >'( (+ 2 3), (+ 2 3) 5 '5 `, (+ 2 3) '(+ 2 3)) ((+ 2 3) (unquote (+ 2 3)) 5 (quote 5) (quasiquote (unquote (+ 2 3))) (quote (+2 3))) > 5 ; les constantes n'ont pas besoin d'être quotées 5 > 5`, ; mais on peut les quoter si l'on veut 5 >(1 2 3) "erreur" … Scheme considère que dans une liste de la forme (e1 e2 e3 ……en) e1 est le nom pour une fonction prédéfini, ou nom chargée dans l'environnement e2 e3 ……en sont les arguments de la fonction e1. Remarque: Quand on est dans l'environnement courant, on définit des fonctions avec define, ces fonctions peuvent être sauvegardées dans un fichier : toto.scm et rechargées dans un environnement ultérieur: 9290058382000147764583820define fonct define var "j'en suis la" 00define fonct define var "j'en suis la" (load "toto.scm") Exemple de programme Scheme: Fichier général : projet.scm 12947655969000220916559690define fonct1 define var1 00define fonct1 define var1 (load "fich1.sc") 1294765199390002209165107950define fonct2 define var2 00define fonct2 define var2 (load "fichn.scm) Tout ceci est aussi valable pour des variables globale ("constantes") Il ne vaut mieux pas modifier les variables globale pendant le déroulement du programme Sous DrScheme: Trace de l'éxécution des programmes sous DrScheme (require-library "trace.ss") ; sa donne acces au fonction trace untrace >(trace + car cdr) essayer aussi directement (step nom_de_fonction) Exercice sur les S-exp: Donner la représentation sous forme d'arbre binaire de la S-exp suivante: ( (1. (2. ( )) ) . ( (3. (4. ( )) ) . ( ) ) ) ainsi que sa notation de liste On considère la session Scheme suivante (cons 0 (quote (1 2) )) (0 1 2) 1. Ecrire cette session avec un . à la place du cons et un ' à la place du quote 2. Ecrire cette session avec des S-exp 92900531750 . 00 . 1) L'arbre conrespondant est le suivant: 2483485145415La notation liste correspondante est la suivante: ( (1 2) (3 4) ) 00La notation liste correspondante est la suivante: ( (1 2) (3 4) ) 111188553975004718055397500 156908576200 . 00 . 2889250 . 00 . 14776459842500175196598425004718051136650019748511366500 56324529210 . 00 . 129476529210 . 00 . 175196529210( ) 00( ) 14605444501 001 3803651428752 002 746125142875( ) 00( ) 746125514350047180551435001569085142875 . 00 . 11118851428753 003 1203325514350014776455143500 1386205958854 004 175196595885( ) 00( ) 14776454445001751965444500 1. On peut écrire l'expression sous la forme suivante: (cons 0 ' (1 2) ) ou encore `(0 . (1 2) ) 2. Sous forme de S-exp cette session s'écrit: >( cons . (0 . (quote . (1. (2 . ( )) . ( ) )) ) ( 0. (1. (2. ( )) ) ) D'ou l'intérêt de la notation de liste pour simplifier cette écriture Atomes et syntaxe de base du langage Scheme Il y a deux sortes de symbole Scheme: Ceux qui sont prédéfinis et constituent la syntaxe de Scheme avec les constantes Ceux qui sont définis par l'utilisateur: très souple, on peut redéfinir des symboles prédéfinis, tout se retrouve dans le même environnement Comme symbole prédéfinis, on a en particulier ceux qui constituent ce que l'on a appelé le "Lisp pur" Les constantes précédemment décrites : S-exp vide () nil, booléens #f #t, nombres, chaîne de caractères, caractères Les fonctions opérant sur les nombres + * - / < = Les fonctions opérant sur les S-exp non atomiques cons . (constructeur), car cdr (selecteur/déconstructeur) avec les règles suivantes: (car ( cons e1 e2 )) e1 (cdr ( cons e1 e2 )) e1 Remarque: (car (e1 . e2 )) e1 (car (e1 . (e2 . (e3 . ( ) ) ))) e1 car (e1 . (e2 . (e3 . ( ) ) )) = (e1 e2 e3 ) (cdr (e1 . e2 )) e2 (cdr (e1 . (e2 . (e3 . ( ) ) ))) (e2 e3 ) (cdr (e1 e2 )) (e2 ) car (e1 e2 ) = (e1 . (e2 . ( ) ) ) avec les arbres: 6546855715 . 00 . 120332527940= e 00= e 47180527940008375652794000 92900550165e2 00e2 28892550165e1 00e1 e1 = car e e2 = cdr e Exemple: (car '(1 . 2) ) ; (ne marche pas sous MzScheme) 1 (cdr '(1 . 2) ) ; (ne marche pas sous MzScheme) 2 (car '(1 2) ) ; (ne marche pas sous MzScheme) (2) Les fonctions de test de type symbol? Pair? (atom?) nomber? Char? String? Comparaison pour les atom eq? La conditionelle if Une fonction servant à dfinir des fonctions sans les nommer lambda La notation traditionnelle d'une fonction est la suivante: xx+1 Cette notation n'est pas pratique au plan symbolique: Dans le -calcul on note: x.x+1 En scheme on notera : ( lambda(x) (+ x 1)) on remarque que la fonction n'est pas nommé Remarques: En Lisp / scheme toute expression différente de () et #f peut être considéré comme le booléen #t (if '(1 2 3) 'oui 'non) oui (if '() 'oui 'non) non (sous MzScheme la réponse est oui) Tout ce qui attend une réponse booléenne (prédicat) ce termine par un ? (number? E) On peut combiner les "a" et les "d" dans car et cdr (car (cdr '(1 2 3))) 2 (cadr '(1 2 3)) 2 Le nombre de "a" et de "b" accepter varie suivant les Scheme Exercice: Calculer (cadadr '( (1 . 2) ( (3 . 4) 5) .6) ) Comment obtenir 3 dans (1 (1 2 3)), (3) dans (1 (1 2 3)) (cadadr '( (1 . 2) ( (3 . 4) 5) .6) ) 5 (caddadr '(1 (1 2 3))) 3 car: (cdr '(1 (1 2 3))) ((1 2 3)) (cadr '(1 (1 2 3))) (1 2 3) (cddadr `(1 (1 2 3))) (3) Autres fonctions prédéfinies très utiles, mais définissables au moyen des précédentes 1+ -1+ (incrémentation, décrémentation) > <= >= (nombres) list append length (S-expressions) reverse last-pair (S-expressions) pair? (test de type) null? equal? (égalité pour les S-expressions quelconque) memq member (appartenance à une liste) assq assoc (appartenance à une liste d'association: traditionnellement ce sont des listes de la forme ( (symb1 . e1) …… (symbn . en) ) où pour 1in symbi est un symbole et ei une S-exp quelconque. Ces listes jouent le rôle des "Record" ("enregistrements") en Pascal. not and or (fonctions booléennes) cond case (fonctions booléennes) Exemple d'utilisation: > (define (atom? n) (not (pair? n))) ; Sous MzScheme on n'a pas atom? > (atom? '(1 2 3)) #f ; C'est une liste > (atom? '() ) ; () est considéré comme un atom #t > (pair? '(1 2 3) ) #t > (pair? '( () ) ) #t > (symbol? (+ 2 3) ) ; 5 est une constante #f > (symbol? (car '(a b)) ) ; a est un symbol #t > (eq? 'a (car '(a b)) ) ; a eq a #t > (eq? '(a) '(a) ) ; eq? ne teste pas les égalité sur les liste #f > (equal? '(a) '(a) ) #t >(eq? (+ 2 3) 5) #t > (null? '(1 2 3) ) #f (null? nil) ; ne marche pas sous Scheme #t > (member '(b) '( (a) (b) (c))) ; reprend la liste à partit de b ((b) (c)) ; utilise equal? , memp utilise eq? > (assoc 'b '( (a 1) (b 2) (a 3))) ; utilise equal? , assq utilise eq? (b 2) > (or #f #f 3 4) ; retourne le premier élément vrai, ici 3 3 ; 4 ne sera pas évalué > (and 1 2 #f 4) ; retourne le premier élément faux, ici #f #f > (cond (#f 1 2) (#t 3 4 5)) ; le premier élément de la première liste étant faux 5 ; il passe a la suivante, quand le premier élément est ; vrai il évalue toute la liste et retourne le dernier ; élément ; on peut se servir du mot réservé :else > (cond (#f 1 2) (#f 3 4) (else (+ 2 3))) ; ici les deux première liste on un ; premier élément qui est faux donc il ; évalué le else > (case (cadr '(a b)) ( (a e i o u y) 'voyelle) ; b n'appartient pas a la liste on évalue ( else 'consonne)) ; donc le else consonne > (list 'a 'b 'c) (a b c) (length (list 'a 'b 'c)) ; retourne la longueur 3 ; sous MzScheme il faut définir lenght > (append '(a b c) '(d e)) ; concatène les listes (a b c d e) > (last-pair (append '(a b c) '(d e))) ; retourne le dernier élément avec un ; niveau de ( ) ; sous MzScheme il faut définir last-pair Exercice : Redéfinir les fonction prédéfinies suivantes: equal? à partir de eq? length member? à partir de equal? last-pair (define (equal? x y) (or (eq? x y) (and (pair? x) (pair? y)) (equal? (car x) (car y)) (equal? (cdr x) (cdr y) )))) (define (length l) (if (null? l) 0 (+ 1 length (cdr l))))) On va maintenant redéfinir la fonction reverse qui renverse une liste au premier niveau: > (reverse '((1 2) 3 (4 5)) ((4 5) 3 (1 2)) (define (reverse l) (if (null? l) l (append (reverse(cdr l)) (list (car l))))) On va maintenant écrire la fonction nreverse qui renverse une liste à tout les niveau (define (nreverse l) (if (atom? l) l (append (nreverse (cdr l)) (list (nreverse (car l) ))))) > (nreverse ((1 2) 3 (4 5)) ((5 4) 3 (2 1) Exercice: Définir les fonction suivantes: (last '(1 2 3)) 3 (nth '((1) (2) (3 4) 5) 3) 3 4 (flatten '((1) (2) (3)) (1 2 3) (deflatten '(1 2 3)) ((1) (2) (3)) Chapitre 4 : fonctionnalité de List et Scheme Le style de programmation: Les programmes ne sont pas constitués de suite d'instructions agissant par effet de bord en modifiant globalement ou localement des variables comme en programmation impérative: ils sont constitué d'ensemble de fonctions. La programmation se faisant alors par composition de ces fonctions, celle-ci communiquant entre elles aux moyens de leurs paramètres Ceci est valable pour tout ce qui n'est pas E/S, c'est à dire pour tout ce qui n'est pas interaction avec l'utilisateur. Not effect property Après exécution d'un programme donné la mémoire se retrouve dans le même état qu'avant l'exécution (Prolog, Scheme) Exemple: Imaginons que l'on veuille calculer le dernier élément d'une liste. Posons la définition suivante: 14776451365251 001 138620513652500> (define (f l) (reverse l) (car l)) f > (f '(1 2 3)) 1 On voit que la fonction ne fonctionne pas car le bloc 1 sera évalué dans un environnement ou l=(1 2 3) mais (reverse l) n'affecteras pas l donc (car l) sera effectué avec l valant (1 2 3) La bonne définition est la suivante: > (define (g l) (car (reverse l))) g > (g '(1 2 3)) 3 On peut aussi définir la fonction de façon impérative de la manière suivante: > (define x '()) x > (define (h l) (set! x (reverse l)) (car x)) h > (h '(1 2 3)) 3 > x (3 2 1) La définition impérative ne respecte pas la Not effect property, et est inutile pour ce genre de programme, mais set! Est indispensable pour le dialogue avec l'utilisateur. Remarque: x est une variable globale ce qui ne pose pas de problème, c'est fonctionnel. C'est le fait de la modifier durant l'exécution de h qui n'est pas fonctionnel. Cours de Programmation fonctionnelle et logique 03.05.2000 Chapitre 4 : fonctionnalité de List et Scheme (suite) Les fonctions nommées On a vu la "fonction instruction" define, cette fonction modifie la variable globale "environnement" prise trouve au méta niveau c'est à dire celui de l'implantation, le niveau objet étant celui de l'utilisateur Pour définir : - des varibles simples (par exemple x=2) des fonctions des variables fonctionnelles (on le verra plus tard) Syntaxe de la construction ( define ( f x1 …… xn) e1 …… em) f : nom de la fonction x1 …… xn : paramètres e1 …… em : corps de la fonction En général m=1, Si m>1 les expressions e1 ,……, em sont alors évaluées pour l'effet de bord qu'elles produisent jusqu'à em non compris. em est vraiment évaluée pour retourner une valeur. Mode d'emploi : Utilisation de define au top level et garder le let, let*, let rec à l'intérieur des fonctions. Question : Quel type de programme peut-on écrire en Scheme ? Tout ce qui est programmable Attention : Il faut que la définition informatique du programme en question aie un certain contenu opérationnel Exemple : Racine_carrée(x) = la valeur y tel que y 0 et y²=x Cette définition est traduisible en Scheme, mais non exécutable car trop déclarative Ceci n'est pas un programme en Scheme Exercice : Prolog étant plus déclaratif que Scheme, trouver un exemple de Programme Prolog qui ne soit pas un programme Scheme. Exemple de définition déclarative qui sont des programmes exécutables en Scheme ( et dans les autres langages de programme actuels) : Les définitions inductives ou récursives On a écrit des interpréteurs capables d'exécuter de telles définitions. 2483485125730Cette définition mathématique déclarative de la somme de 2 entiers issue du schéma de récursion sur les entiers 00Cette définition mathématique déclarative de la somme de 2 entiers issue du schéma de récursion sur les entiers Exemple : Somme (n, 0) = n Somme (n, m+1) = ( Somme (n, m) +1) ( define ( somme n m) ( if ( = m 0 ) n ( + (somme n (-1+ m) ) 1 ))) ; sous MzScheme il faut définir -1+ Remarque : La fonction somme est "totale", en effet elle s'arrêtera sur toute entrée d'entiers car issue du schéma de récursion. En informatique, on appelle une fonction récursive une fonction définie à partir d'elle même et qui s'appellera donc durant son exécution et qui peut fournir des fonctions qui ne s'arrêtent pas pendant leur exécution. Il existe 3 façons de bouclé pour une fonction : Une fonction qui boucle sans rien modifier ( define (f n ) (f n) ) Une fonction qui boucle en remplissant la mémoire de plus en plus ( define (f n) ( + 1 (f n) ) Une fonction qui boucle en construisant une structure de donnée de plus en plus grande (par exemple un entier) ( define (f n) (f (+n) ) ) Remarque : Quel problème pose l'utilisation des fonctions récursive ? Il y a besoin de gérer une pile ( des appels laissés en attente ) pendant l'exécution de la fonction Par exemple : (define (fact n) (if (= n 0) 1 (* n (fact (- n 1))))) Exercice : Ecrire l'exécution (avec trace) de (fact 5) > (fact 5); fact 4 5 ( * ( * ( fact 3) 4 ) 5) ( * ( * ( * ( fact 2) 3) 4) 5) ( *( *( *( * ( fact 1) 2) 3) 4) 5) ( *( *( *( *( * ( fact 0) 1) 2) 3) 4) 5) ( *( *( *( *( * ( 1 ) 1) 2) 3) 4) 5) ( *( *( *( * ( 1) 2) 3) 4) 5) ( *( *( * ( 2) 3) 4) 5) ( *( * ( 6) 4) 5) ( * 24 5) 120 Remarque : Pour éviter la gestion de cette pile, on utilise une technique, dite "des paramètres d'accumulation" ou "récursion terminale", ces paramètres permettant de jouer le rôle de la pile des calculs laissés en attente 2209165125730transformation 00transformation 563245125730Programmation récursive 00Programmation récursive 3397885125730Programmation itérative 00Programmation itérative 211772514795500 3580765100965 exécution 00 exécution 4312285952500 746125100965exécution 00exécution 156908510096500 Ce qui sera incrémenté, ce sont des paramètres de fonctions et non pas des variables globale comme en programmation impérative Exemple: (define ( fact_it n) ( f_it 1 n)) (define (f_it x n) ; x est le paramètre d'accumulation (if ( = n 0) x (f_it (* x n) (- n 1) ))) Exercice : Tracer l'appel de (fact_it 5) Idem avec la fonction de fonction de Fibonnaci a) Definir (fib n) de manière "normale" b) Definir (fib_it n) avec un paramètre d'accumulation > (fact_it 5) f_it (1 5) f_it (5 4) f_it (20 3) f_it (60 2) f_it (120 1) f_it (120 0) 120 a) ( define (fib n) (if (< n 2 ) 1 ( + (fib (- n 1)) (fib (- n 2))))) b) ( define (fib_it n) (f_it 1 1 n)) (define ( f_it x y n) (if (< n 2) x (f_it (+ x y) x (- n 1))))) Exercice : Définir 2 prédicats ent_pair? et ent_impair? Qui testent respectivement si un entier donné est pair ou impair au moyen de fonctions mutuellement récursives. 1. (define (ent_pair? n) (if (= n 0) #t (ent_impair? (- n 1)))) (define (ent_impair? n) (if (= n 0) #f (ent_pair? (- n 1)))) programmer Reverse avec accumulateur Les fonctions sans nom, les lambda expressions. On peut en Scheme définir des fonctions sans les nommer explicitement au moyen de la construction suivante : ( lambda (x1 …… xn) e1 …… em) pour exécuter une telle fonction, on procédera comme pour les fonctions nommées : (f E1 …… Em) (( lambda (x1 …… xn) e1 …… em) E1 …… Em)) Il est possible de nommer ces fonctions anonymes (define f ( lambda (x1 …… xn) e1 …… em)) f est une variable fonctionnelle (define (f x1 …… xn) e1 …… em)) sémantiquement Cas particulier n=m=1 (define f (lambda (x) e)) (define (f x) e) (f E) ((lambda (x) e E) (( (x) e) E) ; x e e [] ;e dans lequel x est remplacer par E val ( e []) ;évalue dans un environnement ou x val(E) Exemple de session > '(lambda (x y) (+ x y)) (lambda (x y) (+ x y)) > (lambda (x y) (+ x y)) # > (lambda (x y) (+ x y) 2 3) # > (define f ( lambda (x y) (+ x y))) f > (f 2 3) 5 275780511938000129476511938000> (define g (lambda (x) (lambda (y) ( + x y)))) g 2757805146050054095651460500129476510604500495236510604500 513524536830Corps 00Corps > ((lambda (f) (f 2)) (lambda (x) (+ 1 x))) 3 > (g 2) ; (y) (+ x y) avec x2 # ; (y) (+ 2 y) 458660539370Paramètre 00Paramètre > ((g 2) 3) 5 Une fonctionnelle est une fonction dont un des paramètres est lui même une fonction Les fonctions comme données. Les Fonctions comme valeurs En Scheme, on peut passer une fonction en argument à une autre fonction (fonctionnelle) Exemple de fonctionnelle très utile : map > (map 1+ '(1 2 3 4 5)) (2 3 4 5 6) > (map (lambda (n) (* n n)) '(1 2 3 4 5)) (1 4 9 16 25) ; on peut redéfinir map très facilement (define (map f l) (if (null? l) l (cons (f (car l)) (map f (cdr l))))) On peut aussi retourner des fonctions comme valeurs résultant de l'évaluation d'expressions Exemples : > (define g (lambda (x) (lambda (y) (+ x y)))) g > ( (g 2) 3) 5 > ( g 2) # ; on peut définir la composition de fonction > (define (compose f g) (lambda (x) (f (g x) ))) compose Exercice: Trouver le résultat de la commande suivante: > ( ( ( lambda (x) (lambda (y) (x y))) (lambda (z) (+ 1 z)) ) 3) x est une fonction (lambda (z) (1+z)) est évalué dans un environnement ou x= (z) (1+z) (x y) est évalué dans un environnement ou x= (z) (1+z) et y = z (+ 1 z) est évalué dans un environnement ou z=3 4 Cours de Programmation fonctionnelle et logique 10.05.2000 Chapitre 4 : fonctionnalité de List et Scheme (suite) Le lambda calcul On a vu les fonctions nommées et anonymes (lambda calcul) On a également vu les fonctionnelles : - Fonction comme donnée en entrée - Fonction comme valeur en Sortie - Données comme fonction (c'est à dire comme programme) Exemple : les booléens On définit: vrai = (lambda (x) (lambda (y) x)) faux = (lambda (x) (lambda (y) y)) On montre ((vrai e1) e2) e1 vrai x (y x) ((faux e1) e2) e2 faux x (y y) Démonstration : ((faux e1) e2) = ( ( ( (x) ((y) y) e1) e2) = ( ( (y) y ) [] e2) = ( ((y) y) e2)= y [] en conclusion ((faux e1) e2) e2 ((vrai e1) e2) = ( ( ( (x) ((y) x) e1) e2) = ( ( (y) x ) [] e2) = ( ((y) y) e1)e2)= e1 [] en conclusion ((vrai e1) e2) e1 On définit alors la conditionnelle "si" de façon à avoir l'équation: (si b e1 e2) = e1 si bvrai e2 si bfaux On peut prendre si = (x y z) ( (x y) z) si' = (x ) ( (y) ( (z) ( (x y) z))) Exercice pour le dossier : Programmer tout ceci en Scheme Après avoir programmer : vrai, faux , si on aura par exemple : > ( si (( lambda (x) x) vrai) "c'est vrai" "c'est faux") vrai Essayer de programmer la factorielle avec cette conditionnelle, idem avec les entiers On peut de même coder les entiers positifs avec des -exp L'idée: l'entier n sera par exemple codé par : (f) ((x) (f (f ( …… (f x) …… ))))) D'autre codage sont possible Quelles sont les équation que l'on voudra avoir : On voudra pouvoir représenter l'addition + par un codage dans le -calcul et avoir l'égalité : x + 0 = x x + (y + 1) = (x +y) + 1 On peut tout représenter dans le -calcul Autre exemple: De même on représente les primitives cons, car et cdr par des -exp Equations a respecter : (car (cons e1 e2)) e1 (cdr (cons e1 e2)) e2 Exercice : Trouver cons, car et cdr avec des -calcul Chapitre 5 : Evaluation des programmes, les définitions locales On va décrire comment sont évalués les expressions ( et programmes) Scheme, l'idée essentielle : Toute l'exécution se déroule dans un environnement ou chaque symbole définit dans la session en cours est lié à une valeur (simple ou fonctionnelle). Ce même environnement servira lors des appels de fonction pour lier des paramètres à leur arguments ainsi que dans les liaisons locales. Environnement: 4037965560070Défini dans la boucle top level ou provenant d'une bibliothèque 00Défini dans la boucle top level ou provenant d'une bibliothèque 2757805742950001460511430cons … fonctions prédéfinies x e argument … … 00cons … fonctions prédéfinies x e argument … … 104140377190x 2 variable globale défini par l'utilisateur fact … variable fonctionnelle défini par l'utilisateur 00x 2 variable globale défini par l'utilisateur fact … variable fonctionnelle défini par l'utilisateur Remarque : Les S-exp servent à représenter : La structure de donnée fondamentale (non atomique) de Lisp (c a d l'arbre binaire) Les définitions de fonctions ( et donc les programme) Les définitions de constantes L'appel de fonction ( et l'exécution des programme) Forme générale des appels de fonction : (e e1…… en) e : expression dont la valeur est une valeur fonctionnelle c'est à dire soit : une -exp explicite un nom pour une fonction prédéfini ou défini au préalable par l'utilisateur e1…… en : argument pour la fonction (n0) A partir du moment ou il n'y a pas de ' Scheme considère que c'est un appel de fonction. Que se passe t-il lors d'un tel appel ? Scheme commence par évaluer les arguments e1…… en (appel par valeur) dans un ordre indifférencié Puis l'expression e est évalué, l'interpréteur reconnaît qu'il s'agit d'une valeur fonctionnelle (sinon "erreur") à n paramètres Il calcule alors le résultat de l'application de e aux valeurs e1…… en en évaluant le corps de la fonction dans un nouvel environnement provisoire ou en plus de l'environnement courant ( celui existant lors de l'appel de la fonction) chaque paramètre xi est lié à la valeur de l'argument ei évalué. L'appel par valeur entraîne des problèmes avec la définition de la condition si par exemple sur la factorielle. A la fin d'une telle évaluation l'environnement initial est restauré (Not effect Property) sauf si la fonction comporte des affectations de variables (set!, do, …) Bien voir que les paramètres d'une fonction sont des variables locales à la fonction : leur portée est le corps de la fonction. Exemple de session : > (define x 2) x > x 2 > (define y 5) y > (define ( f x y) ( x (* y y))) ; f est une fonctionnelle f > (f ( lambda (x) (1+ x)) 3) évaluation de ( x (* y y))dans un environnement ou x ( lambda (x) (1+ x)) y 3 évaluation de (* y y)en 9 évalue x et voit que x ( lambda (x) (1+ x)) évalue (1+ x) dans un environnement ou x 9 10 > x ;x et y retrouve leurs valeurs initiales 2 > y 5 > ( define (g) (+ 2 3)) ;cette fonction n'a pas d'argument g > g # > (g) 5 Le cas des fonctions récursives C'est un peu plus compliqué, la fonction est défini dans un environnement ou elle est censée être lié et faire référence à sa propre définition. (implémentation: on construit des boucles dans l'environnement) Exemple: > (define (f n) (f (+ 1 n))) f > (f 5) ;dans un tel appel le corps de f (f (1+ n)) est évalué ;dans un environnement ou f (n) (f (1+ n)) ;et n 5, ce qui aura pour effet d'appeler (f 6) core Portée lexicale des variables, liaison statique Que se passe-t-il si le corps de la fonction contient des variables qui ne sont pas des paramètres de celle-ci (ni des variables locales : let…) Ou bien ces variables sont liées à la valeur qu'elles ont lors de la définition de la fonction (ça les oblige à être définis à ce moment là) liaison statique Ou bien ces variables sont liées à la valeur qu'elles ont lors de l'exécution de la fonction liaison dynamique Liaison statique tous sauf Lisp et Scheme Liaison dynamique Lisp, Scheme Exemple : > (define y 2) y > (define (p x) (+ x y)) ;y est libre dans p mais liée précédemment dans ; dans l'environnement p > (p 3) 5 > (define y 5) ; on change la valeur de y y > (p 3) 8 ; la valeur de p a changé: il y a donc eu une ; liaison dynamique de variables ;autre exemple avec une variable fonctionnelle > (define (f n) (+ n (g (- n 1)))) f ; g n'est pas lié mais Scheme accepte, liaison ; dynamique > (define (g m) (if (<= m 0) 1 (f (- m 1)))) g > (f 5) 10 > (define (g m) (if (<= m 0) 10 (f (- m 1)))) g > (f 5) 19 ; les variables libres des fonctions (que ce soient des variables simples ou fonctionnelles) sont liées ; dynamiquement dans l'environnement global. ;Lorsqu'il s'agit de variables globales, apparaissant au Top Level, la fonction define opère des liaisons ; statiques, ce qui confère à ces variables, un statut de constantes > (define x 2) x > (define y x) y > y 2 > (define x 3) ;on redéfinit x x > y 2 ; la valeur de y reste inchangée ; même chose pour des variables fonctionnelles > (define f (lambda (x) x)) f > (define g f) g (pp g) ; pp ne marche pas sous MzScheme (define (g x) x) ; g vaut (lambda (x) x) #t > (define f (lambda (x) (xx))) ; on redéfinit f f (pp g) ; pp ne marche pas sous MzScheme (define (g x) x) ; la valeur de g reste inchangée #t ; remarque =( (x) (xx)) ((x) (xx))) Les définitions locales On peut en Scheme utiliser des variables (simples, fonctionnelles) locales dans le corps des fonctions au moyen des fonctions: let, let*, letrec (define) Les liaisons opérées seront statiques Liaison locale let ( let ( (x1 e1) …… (xn en) ) E1 …… Em) (( lambda (x1 …… xn )) E1……Em)e1……En) cas n=m=1 ( let ((x e)) E) ((lambda (x) E) e) "Soit x qui vaut la valeur de E dans E à évaluer" val (E []) Liaison locale let* ( let* ( (x1 e1) …… (xn en) ) E1 …… Em) ( let* ( (x1 e1)) (let* ( (x1 e1)) ( …… ( let* ( (xn en)) …… E1 …… Em)……))) Liaison locale let rec Chaque liaison xi val(ei) intervient dans chaque liaison xj val (ei) i, j n Exemples : > (define x 2) x >(define y 3) > (let ((x (+ 2 3)) (y (* 2 3))) (list x y)) (5 6) > x 2 ;x retrouve sa valeur initiale > y 3 ;y la sienne > ( let ((x (+ 2 3)) (y (* x x))) (list x y)) (5 4) > (let* ((x (+ 2 3)) (y (* x x))) (list x y)) (5 25) > x 2 1660525115570Corps de f 00Corps de f > y 3 1294765508000> (define (f x) (let ((y x)) (+ x y))) 202628521590001751965215900019348452159000f 17519656096000> (f 5) 471805825500471805996950010 16605259525000> (define g (lambda ( x) (let ((y x)) (+ x y)))) 330644542545;On évalue le corps de g dans un ;environnement où x = 5 ;et donc évalue (+ x y) avec x = 5 et y = 5 00;On évalue le corps de g dans un ;environnement où x = 5 ;et donc évalue (+ x y) avec x = 5 et y = 5 230060542545Corps de g 00Corps de g 19348454254500g 4718058191500> (g 5) 10 > x 1111885140970Corps de h de paramètre x 00Corps de h de paramètre x 2 > y 102044536195003 > (define h (let ((y x)) (lambda ( x) (+ x y)))) 26663652286000h 4718056159500> (h 5) 7 > x 2 > y 3 > (letrec ((h (lambda (z) (+ x y z))) (x 5)) (h 10)) 266636538100;Evaluation de l'appel (k 10), k (z) (+ x y z) ;avec z = 10, x = 5, y = 3 ;z: paramètre, x: variable locale, y: variable libre 00;Evaluation de l'appel (k 10), k (z) (+ x y z) ;avec z = 10, x = 5, y = 3 ;z: paramètre, x: variable locale, y: variable libre 18 > (letrec (( fact (lambda (n) (if (= n 0) 1 (* n (fact (- 1 n))) )))) erreur ??? (fact 5)) 120 Autre session montrant que les fonctions let, let*, define, letrec employées localement fournissent des liaisons statiques pour les variables (toutefois certains emplois de define fournissent une liaison dynamique) > (let ((x 1)) (let ((f (lambda (y) (+ x y)))) (let ((x 10)) (f 2)))) 3 ;liaison statique du let : x1 > (define x 2) x > (define (g) ;ne marche pas sous Scheme define x 1 (define f (lambda (y) (+ x y))) ;liaison statique du define employé (define x 10) ;comme un let (f 2)) g > (g) 3 > x ;ceci montre que employé localement le ; define à une portée locale contrairement à set > (define (h x) ;ne marche pas sous Scheme (letrec (( f (lambda (n) (+n (g (-1+ n))))) ;f et g sont mutuellement ((g ( lambda(m) (if (<= m 0) 1 ;récursive, liées statiquement (f (-1+ m) ))))) ;entre elles (f x)))) h > (h 5) 10 > (define g (lambda (n) (if (<= m 0) 10 (f (-1+ m))))) g > (h 5) 10 > (g 3) error: "unbounded variable f"…… ;portée locale du f définie dans le letrec de la fonction h Cours de Programmation fonctionnelle et logique 17.05.2000 Chapitre 6 : Application: implantation du calcul propositionnel Nous allons voir comment représenter des données du calcul propositionnel, puis l'écriture des programmes modulo cette représentation Par Exemple: Représentation d'une fonction de domaine fini f par une liste ((x1 e1)...(xn en)) = Rep(f) où f: x1 ??e1 xn en Comment on programme les opérations sur les fonctions modulo cette représentation: par exemple, comment écrire la composition de fonction gf. Formules propositionnelles, interprétations, substitution... Représentation des formules propositionnelles: Une variable propositionnelle sera représentée par le symbole Scheme correspondant. Le connecteur ? sera représenté par le symbole Scheme non. Les connecteurs ?, ?, ?, ? seront représentés par les symboles et, ou, imp, ssi. Une formule propositionnelles sera alors représentée (en interne) par un arbre binaire (S-exp) en prenant la notation préfixée parenthésée. Exemple : F = ? ? p q ? r rep(F) = (et (ou p q) (non r)) > (define repF '(et (ou p q) (non r))) > (car repF) et > (cadr repF) (ou p q) > (caddr repF) (non r) Exercice : 914400130810 00 Ecrire l'arbre associé à F. 64008014605000109728014605000 45720079375 00 128016079375 00 1463040241300027432024130006400802413000 128016054610 r 00 r 82296054610 q 00 q 18288054610p 00p Exercice : Ecrire l'arbre binaire associé à rep(F). 91440045720 . 00 . 6400804445000120332544450 . 00 . 11118852857500 137160076200009144007620000 73152091440 . 00 . 4572000et 00et 91440030480 . 00 . 9144003048000457200121920ou 00ou 6400803048000 1188720137160 . 00 . 91440013716000118872013716000 2286000152400 . 00 . 73152060960p 00p 1463040762000011887207620000 246888091440002103120914400014630400( ) 00( ) 10058400q 00q 1828800106680 . 00 . 265176018415( ) 00( ) 201168021590 . 00 . 210312021590001645920113030non 00non 18288002159000 228600011557000210312011557000 228600027305( ) 00( ) 192024027305 r 00 r Exercice : Définitions inductives rep(v) = v si v?P rep(?G) = (non rep(G)) rep(? G H) = (et rep(G) rep(H)) de même pour les autres connecteurs binaires Formule notation préfixe ? représentation préfixe parenthésée de Scheme Autre possibilité de représentation des formules propositionnelles: Formule notation infixe ? représentation infixe parenthésée de Scheme rep'(v) = v si v?P rep'(?G) = (non rep'(G)) rep'(G ? H) = (rep'(G) et rep'(H)) Programmes calculant sur les formules propositionnelles rep(F) On utilise des variables globales pour ranger les connecteurs %lc ? liste des connecteurs %lcu ? liste des connecteurs unaires (non) %lcb ? liste des connecteurs binaires (et, ou, imp, ssi) Exemple : ; fonction de test morphologique pour les formules propositionnelles ; écrites avec rep (define (test s) (if (atom? s) (not (member s %lc)) (let ((c (car s)) (l1 (cdr s))) (if (null? l1) #f (let ((G (car l1)) (l2 (cdr l1))) (if (null? l2) (and member c %lcu) (test G)) (let ((H (car l2)) (l3 (cdr l2))) (if l3 #f (and (member c %lcb) (test G) (test H)))))))))) Exemple : ; fonction de traduction des formules propositionnelles de la forme ; préfixe parenthésée: rep vers la forme infixe parenthésée rep' et ; inversement: rep'(F) rep(F) ; la même fonction trad(F) marche dans les deux sens (define (trad F) (if (atom? F) F (let ((x (car F)) (y (cadr F)) (z (cddr F))) (if (null? z) '( ,x,(trad y)) '( ,(trad y), (trad x), (trad(car z))))))) Exercice (avec rep(F)) Ecrire une fonction "hauteur", qui calcule la hauteur de la formule F (= longueur de la branche la plus longue de l'arbre associé à la formule en comptant la racine) Ecrire une fonction "longueur" qui calcule la longueur d'une formule F. Ecrire une fonction "degre" qui calcule le degré d'une formule F. (define (haut F) (if (atom? F) 1 (let ((G (cadr F)) (l (cddr F))) if (null? l) (1+ (haut G)) (1+ (max (haut G) (haut (car l)))))))) (define (long F) (if (atom? F) 1 (let ((G (cadr F)) (l (cddr F))) if (null? l) (1+ (long G)) (1+ (+ (long G) (long (car l)))))))) (define (degre F) (if (atom? F) 0 (let ((G (cadr F)) (l (cddr F))) if (null? l) (1+ (degre G)) (1+ (+ (degre G) (degre (car l)))))))) On se rend compte qu'on a écrit trois formules quasiment identiques. On en déduit une fonctionnelle de décomposition des formules propositionnelles Cas simple: les connecteurs ne seront pas distingués les uns des autre. ; fonctionnelle de décomposition ; F représente une formule propositionnelle ; x une expression quelconque ; y une fonction à 1 argument qui doit être une formule ; z -------------- 2 ---------------------------------- (define (decomp F x y z) (if (atom? F) x (let ((G (cadr F)) (l (cddr F))) (if (null? l) (y G) (let ((H (car l))) (z G H)))))) (define (haut F) (decomp F 1 (lambda (x) (1+ (haut x))) (lambda (xy) (1+ (max (haut x) (haut y)))))) (define (long F) (decomp F 1 (lambda (x) (1+ (long x))) (lambda (xy) (1+ (+ (long x) (long y)))))) (define (long F) (decomp F 0 (lambda (x) (1+ (long x))) (lambda (xy) (1+ (+ (long x) (long y)))))) Exercice : Utiliser la fonctionnelle decomp pour calculer la liste des variables propositionnelles apparaissant dans F (define (listvar F) decomp F (list F) (lambda (x) (listvar x)) (lambda (xy) (append (listvar x) (listvar y)))))

Related Downloads
Explore
Post your homework questions and get free online help from our incredible volunteers
  1261 People Browsing