Le langage LISP Université AbouBakr Belkaid -Tlemcen Ecole doctorale STIC option SIC - Module : Intelligence Artificielle Amine Brikci-Nigassa 05/06/2007 Plan Introduction Historique Particularités Utilisation en IA Petit exemple : Morpion Conclusion Introduction Le plus ancien des langages de haut niveau actuels, après FORTRAN Souvent associé à l'IA Regain d'intérêt depuis quelques années Sort du commun : différent des langages dérivés d'ALGOL (Pascal, C, Java...) Ses concepts simples et puissants => Apprentissage enrichissant Introduction Capacités puissantes. Nombreuses améliorations => Applications multiples. Simplicité, Faible nombre de mots-clés, Interactivité => Permet l'initiation à la programmation pour les non-informaticiens. Historique 1958 : Pr John Mac Carthy (MIT), inventeur du terme «intelligence artificielle» crée le LISt Processing language : application du Lambda-calcul de A. Church. => Nouveau paradigme: programmation fonctionnelle Nombreuses nouveautés, dont: structure si-alors-sinon ramasse-miettes (garbage collector) => influence sur ses successeurs, dont les futurs langages objet (Smalltalk, Java...) Historique Inconvénient de la programmation fonctionnelle : trop gourmand en ressources pour les machines de l'époque Evolution => les dialectes de Lisp : Common Lisp : riche, complexe, normes ANSI Scheme : épuré, normes IEEE => de nombreuses implémentations (interpréteurs et/ou compilateurs) multiplateformes et Libres/Open Source Emacs Lisp : intégré dans GNU Emacs ... Le langage pour enfants Logo est dérivé de Lisp Particularités de Lisp Programmation fonctionnelle : Programmation impérative (Fortran, C...): changements successifs de l'état de la machine (variables) Programmation fonctionnelle: les valeurs manipulées passent d'une fonction à l'autre (paramètres/retour) Une fonction appelée avec les mêmes valeurs plusieurs fois retourne toujours le même résultat: pas d'effets de bord Lisp n'est pas un langage fonctionnel pur (aussi un langage impératif => effets de bord possibles) Particularités de Lisp Langage "fortement" récursif : Nature fonctionnelle => facilite l'usage de la récursivité. Les structures de boucles sont peu utilisées Problème : risques de débordements de pile valeurs intermédiaires empilées à chaque appel: Programme : (define (fact n) (if (zero? n) 1 (* n (fact (- n 1))) ) ) L'appel à fact est "enveloppé" dans l'appel à la fonction * Trace des calculs : (fact 4) (* 4 (fact 3)) (* 4 (* 3 (fact 2))) (* 4 (* 3 (* 2 (fact 1)))) (* 4 (* 3 (* 2 (* 1 (fact 0))))) (* 4 (* 3 (* 2 (* 1 1)))) (* 4 (* 3 (* 2 1))) (* 4 (* 3 2)) (* 4 6) 24 Particularités de Lisp Solution : récursion terminale Programme : Trace des calculs : (define (iterer n a) (if (<= n 1) a (iterer (- n 1) (* a n)) ) ) (define (fact n) (iterer n 1)) (fact 4) (iterer 4 (iterer 3 (iterer 2 (iterer 1 24 1) 4) 12) 24) Les résultats intermédiaires sont passés en argument L'appel récursif doit être terminal, ne doit pas laisser une fonction attendre le résultat pour finir L'interpréteur/compilateur peut aisément convertir la récursion terminale en itération Particularités de Lisp Principale structure de données : la Liste Liste = chaîne de doublets de pointeurs 1ère implémentation (IBM 704): doublets accessibles dans les registres CPU par 2 macros ASM: car (contents of address register) donne l'adresse d'un élément de la liste cdr (contents of decrement register) donne l'adresse du doublet suivant Cette liste est notée (1 2 3) 1 2 Le dernier cdr contient l'adresse "NIL" notée () 3 Particularités de Lisp Les élements d'une liste peuvent être des atomes ou des listes (=> arborescence) A 1 2/7 "foo" 3.14 liste L : (1 (2/7 3.14) A "foo") Le 2ème élément, noté (car (cdr L)) ou (cadr L) est la liste (2/7 3.14) Particularités de Lisp Un doublet n'est pas toujours un élément d'une liste: 1 2 cette "paire" (ou "cons") est notée (1 . 2), elle est construite avec l'appel de fonction (cons 1 2) ce n'est pas une liste Particularités de Lisp Les expressions arithmétiques et les appels de fonctions sont des listes: notation préfixée parenthésée (=> pas de priorité des opérateurs) + exp 1 e x x x / 1 s'écrit (+ (exp x) (/ 1 (sqrt x))) + exp / et sqrt sont des fonctions sqrt x Particularités de Lisp Nature d'un programme Lisp Les programmes sont des ensembles de fonctions, dont l'appel se fait par des listes : (fonct param1 param2 ...) L'exécution d'un programme revient à l'évaluation d'une fonction principale. Le programme source étant lui-même une liste, il est facilement manipulable (métaprogrammation) Particularités de Lisp Exécution d'un programme Lisp : La boucle read-eval-print read : programme source --> structure de liste (compilateur --> byte code ou langage machine) eval : la structure est évaluée (retourne une structure en résultat): chaque argument du cdr est d'abord évalué (peut être lui-même une fonction) la fonction désignée par le car leur est appliquée print : l'affichage du résultat peut être simple (atome) si c'est une liste, il faudra d'abord la parcourir. Particularités de Lisp Garbage Collecting (ou Glanage de Cellules) Les structures de données occupent de la mémoire, qui n'est pas manipulée explicitement par l'utilisateur Pour éliminer les données inutilisées de la mémoire, Mc Carthy invente le Garbage Collector (ramasse-miettes): processus automatique qui libère la régulièrement les cases mémoire non référencées Pas de souci de "désallocation" => moins de bugs L'idée est reprise dans de nombreux langages (Smalltalk, Java...) Utilisation en IA Nature fonctionnelle + Manipulation des listes/arbres => programmation exploratoire utile en IA Particulièrement adapté pour programmer: les analyseurs syntaxiques (comme celui du 1er compilateur Lisp !), les systèmes experts, réseaux de neurones, algorithmes génétiques, agents intelligents, systèmes de gestion des connaissances, etc... Utilisation en dehors de l'IA Lisp est adapté à bien d'autres domaines: l'animation et les graphismes, la bioinformatique, le e-commerce, le data mining, les applications pour EDA/Semiconducteurs, les finances, la CAO mécanique, la modélisation et la simulation, le langage naturel, l'optimisation, l'analyse des risques, l'ordonnancement, les télécommunications, et le Web Authoring... Petit exemple : Morpion (define (morpion) (boucle '((- - -) (- - -) (- - -)) 'X 'O)) (define (boucle matrice joueur1 joueur2) (print "position pour le " joueur1 " ?") (let ((ligne (saisie "ligne: "))) (if (eqv? ligne 'q) 'abandon (let* ((colonne (saisie "colonne: ")) (new-matrice (nouveau matrice ligne colonne joueur1))) (newline) (affiche-matrice new-matrice) (newline) (cond ((gagne? new-matrice) (display "le gagnant est : ") joueur1) ((partie-nulle? new-matrice) (display "partie nulle !!! ") 'Fin) (else (boucle new-matrice joueur2 joueur1))))))) (define (saisie message) (display message) (read)) (define (gagne? m) (or (identiques? (identiques? (identiques? (identiques? (identiques? (identiques? (identiques? (identiques? (car (car m)) (cadr (car m)) (caddr (car m))) (car (cadr m)) (cadr (cadr m)) (caddr (cadr m))) (car (caddr m)) (cadr (caddr m)) (caddr (caddr m))) (car (car m)) (car (cadr m)) (car (caddr m))) (cadr (car m)) (cadr (cadr m)) (cadr (caddr m))) (caddr (car m)) (caddr (cadr m)) (caddr (caddr m))) (car (car m)) (cadr (cadr m)) (caddr (caddr m))) (car (caddr m)) (cadr (cadr m)) (caddr (car m))))) Petit exemple : Morpion (define (identiques? a b c) (and (equal? a b) (equal? b c) (not (equal? A '-)))) (define (partie-nulle? (and (not (member '(not (member '(not (member '- m) (car m))) (cadr m))) (caddr m))))) (define (nouveau m i j joueur) (new-ligne m i (new-ligne (nieme m i) j joueur))) (define (new-ligne l i val) (cond ((null? l) '()) ((= i 1) (cons val (cdr l))) (else (cons (car l) (new-ligne (cdr l) (- i 1) val))))) (define (nieme l i) (if (= i 1) (car l) (nieme (cdr l) (- i 1)))) (define (affiche-matrice m) (print " " (caar m) " | " (cadar m) " | " (caddar m)) (print "---+---+---") (print " " (car (cadr m)) " | " (cadr (cadr m)) " | " (caddr (cadr m))) (print "---+---+---") (print " " (car (caddr m)) " | " (cadr (caddr m)) " | " (caddr (caddr m)))) Petit exemple : Morpion nh2@debian:~$ bigloo -----------------------------------------------------------------------------Bigloo (2.6e) ,--^, `a practical Scheme compiler' _ ___/ /|/ Tue Oct 19 12:13:41 CEST 2004 ,;'( )__, ) ' Inria -- Sophia Antipolis ;; // L__. email: [email protected] ' \ / ' url: http://www.inria.fr/mimosa/fp/Bigloo ^ ^ -----------------------------------------------------------------------------Welcome to the interpreter 1:=> (load "morpion.scm") morpion boucle saisie gagne? identiques? partie-nulle? nouveau new-ligne nieme affiche-matrice morpion.scm 1:=> Petit exemple : Morpion 1:=> (morpion) position pour le X ? ligne: 2 colonne: 2 - | - | ---+---+--- | X | ---+---+--- | - | position pour le O ? ligne: 1 colonne: 1 O | - | ---+---+--- | X | ---+---+--- | - | position pour le X ? ligne: Petit exemple : Morpion position pour le X ? ligne: 2 colonne: 3 O | - | X ---+---+--- | X | X ---+---+--O | - | position pour le O ? ligne: 2 colonne: 1 O | - | X ---+---+--O | X | X ---+---+--O | - | le gagnant est : O 1:=> Petit exemple : Morpion 1:=> (gagne? ((O O O) (X - X) (- - -))) *** ERROR:bigloo:eval: Unbound variable -- O #unspecified 1:=> (gagne? '((O - X) (- O X) (X X O)) ) #t 1:=> (affiche-matrice '((O - X) (- O X) (X X O)) ) O | - | X ---+---+--- | O | X ---+---+--X | X | O O 1:=> (nouveau '((O - X) (- O X) (X X -)) 3 3 'O) ((O - X) (- O X) (X X O)) 1:=> (nieme '((O - X) (- O X) (X X -)) 2) (- O X) Conclusion Lisp is worth learning for the profound enlightenment experience you will have when you finally get it; that experience will make you a better programmer for the rest of your days, even if you never actually use Lisp itself a lot. Eric S. Raymond, "How to Become a Hacker" Lisp vaut la peine d'être appris pour l'expérience profondément enrichissante que l'on obtient quand on finit par l'assimiler. Cette expérience là fera de vous un meilleur programmeur pour le restant de vos jours, même si vous n'utilisez jamais vraiment Lisp lui-même énormément.