Prg fonctionnelle et
logique
2ème Année Filière Informatique
Khaled Ben Lamine
2018-2019
Plan
• Donner une vue globale sur les langages et les
paradigmes de programmation avec une focalisation sur
deux paradigmes qui sont la programmation fonctionnelle
et la programmation logique
1. Historique des langages de programmation
2. Paradigmes de programmation
3. La programmation fonctionnelle
4. La programmation Logique
Historique:
Les pionniers de la programmation
• Charles Babbage (1791-1871):
Invente la « machine analytique ». Sa compagne, Ada
Augusta Lovelace, est considérée comme la première
programmeur.
• Konrad Zuse (1942):
Développe Plankalkül. Cette notation (implémentée
seulement en 1975 à titre historique) fut un précurseur
des langages de programmation.
Historique:
Langages de très bas niveau
• Ces langages machines et assembleurs sont dépendant
du hardware. Initialement binaires, puis éventuellement
symboliques.
• Il y a un unique langage machine, et habituellement un
seul langage assembleur pour chaque type de
processeur.
• La compatibilité ascendante est souvent très difficile: Aller
des 386 vers 486 , ou du 486 aux Pentium, ….
Historique:
Fortran: 1954-1990
• Le premier langage de haut niveau à avoir été implémenté et ayant introduit
les variables, tel que nous les connaissons, les boucles, procédures,
étiquettes…
• Développé pour le calcul scientifique.
• La première version avait plusieurs caractéristiques uniques, souvent
disgracieuses, mais conservées pour maintenir une compatibilité
descendante.
• Encore utilisé pour des applications d’ingénierie nécessitant beaucoup de
manipulations de tableaux et bénéficiant d’une bibliothèque importante de
programmes
• La dernière version, Fortran 90, converge vers les autres langages de
programmation.
Historique:
Algol 60
• Le premier langage à introduire les blocs et la récursivité,
et à être défini formellement. N’est plus utilisé mais est un
ancêtre de plusieurs langages contemporains.
• Souvent considéré comme le langage le plus innovateur
de l’histoire des langages de programmation.
Historique:
Cobol
• Orienté vers le traitement de données (applications de gestion)
• Organisation très stricte
• Structures de contrôles faibles
• Structures de données élaborées, les enregistrements (records)
sont introduits.
• Populaire dans le monde des affaires et des services
gouvernementaux, moins dans les universités.
• A vécu un regain d’intérêt lors de la « crise » du bug du passage à
l’an 2000.
Historique:
PL/I
• Une combinaison des meilleurs éléments (tel qu’on
pensait à l’époque) de Fortran, Algol 60 et Cobol.
• Conçu pour être complètement général, pour être
utilisé pour toute application de l’époque.
• Encouragé par IBM
• Peu utilisé aujourd’hui.
• Introduit la manipulation d’événements (event handling).
Historique:
Basic
• Le premier langage utilisé en informatique personnelle
(personal computing).
• Le premier langage appris par plusieurs programmeurs:
Conçu pour être facile à apprendre.
• Très simple, puissance limitée, mais peut être utilisé dans
plusieurs domaines d’applications.
• Les versions de Basic utilisées aujourd’hui sont plus
complexes.
Historique:
Simula 67
• Une extension d’Algol 60 conçu pour la simulation de
processus concurrents.
• Introduit les concepts de programmation orientée objet:
classes et encapsulation.
• Prédécesseur de Smalltalk et C++.
• N’est plus très utilisé.
Historique:
Algol 68
• Sa conception est d’une élégance toujours inégalée.
• Très difficile à implémenter.
• Une description formelle habile, mais difficile à
comprendre.
• Jamais vraiment utilisé.
Historique:
Pascal
• Une version simplifiée d’Algol 68.
• Populaire pour l’enseignement de la programmation
structurée.
• Un « bon » « premier langage » à apprendre, favorise de
bonnes habitudes de programmation.
• Ses extensions (comme Delphi) sont des systèmes de
programmation complets, aussi puissant que des
environnements Java, par exemple.
Historique:
Modula-2
• Un successeur de Pascal, plus conceptuellement
uniforme.
• Mécanismes de programmation concurrente (plusieurs
processus en parallèle).
• Peu utilisé, bien que ce soit un bon langage.
• Ses successeurs, Modula-3 et Oberon, sont encore plus
attrayants, pratiques — et peu utilisés, (supplantés par
C++.)
Historique:
Ada
• Le résultat d’un processus de conception très élaboré, à
plusieurs étapes, et une tentative plus réussie que PL/I
d’obtenir un langage général.
• Complètement standardisé: ne possède aucun dialecte
( tout comme Java).
• 2 standards: Ada 83 (original), et Ada 95.
• Permet la concurrence de façon élégante et
systématique.
Historique:
C
• Utilisé pour implémenter Unix.
• Utile pour la programmation système et le développement
pour les ordinateurs personnels.
• Populaire dans le passé, toujours utilisé, mais supplanté
par C++.
• De bas niveau / haut niveau.
Historique:
LISP
• Un des premiers langages de programmation.
• Basé sur l’évaluation de fonctions. Utile pour le calcul
symbolique.
• Initialement l’unique langage de l’intelligence artificielle
(Prolog est plus jeune de 12 ans).
• Plusieurs dialectes: Scheme, Common Lisp.
• Des successeurs très élégants (Miranda, ML, Haskell)
mais peu utilisés.
Historique:
Prolog
• Un langage de très haut niveau.
• Déclaratif, basé sur un sous-ensemble de la logique, les preuves
sont interprétées comme les calculs.
• Puissant:
• Gère le Non-déterminisme (backtracking intégré).
• Appariement flexible et élaboré.
• Mémoire Associative: accès par le contenu
• Un outil puissant, entre des mains habiles.
Historique:
Smalltalk
• Programmation orientée objet très pure (plus que Java,
beaucoup plus que C++).
• Intégré à un environnement de programmation et une
interface usagée.
• Un outil puissant, entre des mains habiles.
Historique:
C++
• L’extension orientée objet du langage impératif C.
• De conception hybride, avec les concepts orientés objet
ajoutés à un langage qui n’était pas conçu pour cela.
• Syntaxe compliquée, sémantique difficile.
• Très en vogue et en demande. Java ne l’a pas encore
supplanté, classé comme le langage le plus demandé en
2016,
Historique:
Java
• Une version modifiée de C++ beaucoup plus élégante.
• Pleinement orienté objet (Quoi que pas aussi consistant
que Smalltalk)
• Conçu pour la programmation pour Internet, mais
d’utilisation générale.
• En vogue.
Historique:
Langage Script
• Traitement de fichiers texte
• Perl
• Python
• Programmation du web
• JavaScript
• PHP
Historique:
Spécialisation d’un Langage
• Langages à usage général:
• la plupart des langages que vous connaissez,
• Langages spécialisés: par exemple
• Matlab; Octave (mathématiques),
• Cobol (production de rapports),
• SQL (bases de données),
• Perl (adapté au traitement et à la manipulation de fichiers texte,
langage interprété intermédiaire entre C et des langages script
comme Shell ou Sed) ,
Historique:
Liens Historiques entre les Langages
Historique:
Liens Historiques entre les Langages
Historique:
Liens Historiques entre les Langages
Historique:
Classement des Langages de Programmation:
Historique:
Classement des Langages de Programmation:
• Se limiter aux dix premiers est un choix très difficile dans la mesure où
la suite du classement est également intéressante.
• On retrouve par exemple de la 11e à la 20e place :
• Arduino (#11),
• Ruby (#12),
• Assembleur (#13),
• Scala (#14),
• Matlab (#15),
• HTML (#16),
• Shell (#17),
• Perl (#18),
• Visual Basic (#19)
• Cuda (#20).
SOMMAIRE
1. Introduction
2. Aperçu Historique
3. Paradigmes de Programmation
4. Programmation fonctionnelle
5. Programmation logique
Paradigmes de programmation
Définition
• Un Paradigme est un modèle de pensée qui oriente la
recherche et la réflexion scientifique (Larousse)
• Un paradigme de programmation est une façon de penser
qui oriente l’analyse, la conception et le codage d’un
programme,
• Chaque paradigme permet d’autres techniques de
programmation: Les paradigmes sont complémentaires
Paradigmes de programmation
classification
• Le nombre de paradigmes est
de l’ordre de 29 paradigmes
réellement utilisés, mais le
nombre de LP est beaucoup
plus important,
• Chaque paradigme est défini
par un ensemble de concepts
de programmation,
Paradigmes de programmation
classification
• 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 étaient voué au calcul numérique
opposé au calcul symbolique.
Paradigmes de programmation
classification
• Programmation impérative:
• ce type de programmation présente 3 propriétés:
• traitement séquentiel des instructions,
• usage de variables représentant des espaces mémoires ou des états,
• usage d’affectations pour changer les valeurs des variables, ou les états
• Exemples: Pascal, C, C++, Java ….,
• Programmation déclarative:
• ce type de programmation permet au programmeur de déclarer diverses entités
sans se soucier de la façon dont celles-ci seront utilisées. Le programme pourra
ensuite utiliser ces déclarations pour résoudre le problème, exemples: Prolog, Lisp
Paradigmes de programmation
Classification
Paradigmes de programmation
Classification
Paradigmes de programmation
Programmation Impérative
• Programmation procédurale:
• Le programme est divisé en blocs pouvant contenir des variables
locales, ainsi que d’autres blocs: (Fortran, Pascal, C,),
• la programmation est basée sur des instructions/commandes “fais
quelque chose”,
• Programmation orientée objet:
• Des objets se rapportant au problème sont définis, avec leurs attributs
et leur façon de réagir à différents événements,
• Le problème est résolu grâce à des structures de contrôles basées sur
l’envoi de messages entre ces objets: (Java, Smalltalk, C++, C#, Eiffel)
Paradigmes de programmation
Programmation Impérative
• Programmation concurrente:
• Langage permettant la mise en œuvre de plusieurs activités concurrentes
pouvant s’exécuter simultanément, communiquer et se synchroniser entre
elles. Les données peuvent être partagées ou pas: cas de Ada 95, ou Java
• Programmation évènementielle:
• la logique du programme est commandée par l’apparition d’évènements
auxquels il faut répondre,
• elle est souvent basée sur l’approche objet,
• un événement est souvent le résultat d’une intervention de l’utilisateur: clic,
déplacement de souris, …: cas de Java
Paradigmes de programmation
Programmation déclarative
• Programmation fonctionnelle:
• Un programme consiste en la déclaration de fonctions,
• La structure de contrôle se résume en l’application et
l’évaluation de fonctions,
• Un appel à une fonction est fait. Celle-ci retournera un élément
qui ne dépend que de la valeur des paramètres de la fonction.
Les paramètres peuvent, eux même, être des appels à des
fonctions: Lisp, Haskell, Scala, Erlang, Java+Guava, F#
• Les paramètres de fonctions peuvent être des appels de
fonctions,
Paradigmes de programmation
Programmation déclarative
• Programmation logique:
• Un programme consiste en la déclaration d’une série d’axiomes et de règles de
déduction, avec la présentation d’un théorème à prouver. Le programme répond
si le théorème peut être prouvé ou non à partir des déclarations: (Prolog),
• Tout est défini en terme de prédicats logiques,
• La structure de contrôle est implicite: unification et chainage arrière,
• Programmation à base de contraintes:
• utilise le principe de la programmation logique,
• orientée but: résolution de contraintes, généralement sous forme
Paradigmes de programmation
Langages Multi Paradigmes
• De plus en plus de langages sont multi-paradigmes: C++,
Python, Oz, Ruby, Ocalm, F#….
• Extensions orienté objet: non seulement C++, mais les
dialectes de Lisp (CLOS) et Prolog (XPCE/Prolog, Prolog++).
• Programmation logique combinée à la programmation
fonctionnelle (encore expérimental).
• Langages concurrents (comme Ada): au lieu d’avoir un
processus sur un processeur, permet plusieurs processus
en parallèle.
SOMMAIRE
1. Introduction
2. Aperçu Historique
3. Paradigmes de Programmation
4. Programmation fonctionnelle
5. Programmation logique
Programmation
fonctionnelle
• Objectif général
• Découverte de la programmation fonctionnelle
• Les formes qu'elle prend syntaxiquement (expressions, fonctions et
listes récursives)
• Compétences générales attendues
• Spécifier un calcul de façon fonctionnelle plutôt qu'impérative :
programmer au moyen d'expressions plutôt que d'instructions
• Spécifier des calculs récursivement plutôt qu'itérativement
• Spécifier un calcul générique : abstraire un calcul au moyen de
paramètres fonctionnels et de retours fonctionnels
Concepts fonctionnels
• Ecriture fonctionnelle : programmation par applications
de fonctions plutôt que par l'exécution de séquences
d’instructions
• Transparence référentielle : chaque expression peut
être remplacée par son résultat sans changer le
comportement du programme - sans effets de bord
• Programmation fonctionnelle pure : sans effets de
bords, avec transparence référentielle.
Concepts fonctionnels
• Flot de contrôle non linéaire: si aucune dépendance ne
les lie, deux fonctions peuvent être appelées dans
n’importe quel ordre,
• Evaluation retardée: selon le besoin
• Garbage collector: ramasse miette au niveau de la
mémoire
• Inférence de type: Déterminer automatiquement le type
d'une expression ou d'une fonction
Historique
• 1958 : John Mac Carthy (MIT)
• 1986 : common lisp ANSI (portabilité, consistance, expressivité, efficacité, stabilité).
• Les enfants de lisp :
• Logo (1968), langage visuel pédagogique
• Smalltalk (1969, Palo Alto Research Center de Xerox) premier langage orienté objets
• ML (1973, R. Milner, University of Edinburgh), preuves formelles, typage statique, puis
CaML (1987 INRIA), projet coq, et Haskell purement fonctionnel, paresseux.
• Scheme (1975, Steele et Sussman MIT) mieux défini sémantiquement, portée lexicale,
fermeture, et continuations de première classe.
• emacs-lisp (Stallman 1975, Gosling 1982), langage d'extension de GNU Emacs.
• CLOS (1989, Common Lisp Object System), common lisp orienté objets.
Programmation fonctionnelle
concepts de base
• Exemple:
• Soit la fonction factorielle:
‘‘ n! est le produit des entiers entre 1 et n’’
ou
n! = 1 * … * n ou n! = ∏ i , ∀ i ∈ [1, …,n]
ou
0! = 1 et n ! = n * (n – 1) !, si n>0
Programmation fonctionnelle
concepts de base
Programmation fonctionnelle
concepts de base
• Le paradigme fonctionnel
n'utilise pas de machine à
• Le paradigme impératif états pour décrire un
s’appuie sur le modèle de programme, mais un
machine à états (ou de Turing) emboîtement de fonctions qui
avec une mémoire centrale et se présentent comme des
des instructions qui modifient « boîtes noires » que l'on peut
son état grâce à des imbriquer les unes dans les
affectations successives: autres: pas de variable, pas
affectation, variables d’affectation
Programmation fonctionnelle
concepts de base
• La sortie S ne dépend que des entrées E1, E2, ……, En
• Pour le même n-uplet en entrée E1, E2, …, En, la sortie est toujours
la même
Programmation fonctionnelle
concepts de base
• L’exécution d’un programme fonctionnel comprend l’évaluation d’une
expression symbolique dite s-expression.
• Souvent, il y a un environnement interactif qui permet l’évaluation d’une
expression entrée par l’utilisateur (comme c’est le cas avec une machine à
calculer).
• On appelle session le cycle continu de:
• entrer une expression,
• et de la laisser évaluer.
• Les expressions contiennent généralement des références aux fonctions
prédéfinies dans une bibliothèque ou définies par le programmeur dans un
script.
Paradigme fonctionnel
concepts de base
• L’évaluation d’une expression consiste en la simplification de l’expression à
sa plus simple forme équivalente.
• Une expression qui ne peut plus être simplifiée est dite sous sa forme
canonique.
• Le processus de simplification repose sur l’usage des définitions comme
règles de réécritures : si l’expression à simplifier est une instance de la
partie gauche d’une définition (= pattern matching), elle se simplifie à la
partie droite de la règle sous la substitution appropriée.
• On appelle réduction une séquence d’expressions e1, . . . , en dont chaque
expression ei (i >= 2) est une simplification de ei−1 obtenue en appliquant
une seule définition.
• Une réduction e1, . . . , en est dite totale quand en est en forme canonique.
Paradigme fonctionnel
concepts de base
• En général, on peut construire plusieurs réductions pour une seule
expression..
square (3 + 4)
square (3 + 4) =
= (3 + 4) * (3 + 4)
square 7 =
= 7 * (3 + 4)
7*7 =
= 7*7
49 =
49
• Une caractéristique-clef de la programmation fonctionnelle est:
• Si on peut construire différentes réductions totales pour une seule expression,
elles résultent toutes à une même forme canonique: le résultat est toujours le
même.
• Il est possible qu’une réduction ne se termine pas.
Programmation Fonctionnelle
Concepts de base – Principe1: tout est fonction
• Fonction: au sens mathématique
• f : x —> x
• f : x—> 3 . x ou f(x) = 3 . x
• Lambda-calcul:
• λx.x
• (λx. 3 * x) 9 —> 3 * 9
Programmation Fonctionnelle
Concepts de base – Principe1: tout est fonction
• Contrairement aux mathématiques, les L.P font la différence entre la définition de la
fonction et l’application de la fonction:
• Définition de la fonction: déclaration de la fonction et la description de ce qu’elle
doit faire, en utilisant des paramètres formels,
• Application de la fonction: appel de la fonction déclarée utilisant les paramètres
actuels ou « arguments »,
• Mathématiques vs L.P. Impératifs:
• En L.P. impératifs, les variables réfèrent à une adresse mémoire et une valeur ,
• En mathématiques, les variables représentent toujours la valeur actuelle, d’où une
expression comme x:= x + 1 n’a pas de sens,
L’approche fonction dans la programmation doit donc éliminer la notion de variable
et par voie de conséquence l’opération d’affectation
Programmation Fonctionnelle
Concepts de base – Principe1: tout est fonction
• Un programme comme description d’un traitement spécifique doit permettre de rendre
compte de:
• Le « comment » du traitement: ce qui doit être fait!!
• Le pourquoi du traitement: quel résultat attendu !!
• De ce fait, Un programme n’est autre qu’une fonction mathématique:
• Vision fonction
• Vision programme / procédure
• f: X —> Y, à chaque x de X, associe un y
de Y • X est l’ensemble des entrées
du programme / paramètres
• X est l’ensemble domaine de f,
• Y est l’ensemble des résultats
• Y est l’ensemble image de f, du programme / valeurs
retournées
• y = f(x) ; x est dite variable indépendante,
y est dite variable dépendante
Programmation Fonctionnelle
Concepts de base – Principe2: récursivité
• L’itération est proscrite:
for
While
…
• L’itération remplacée par une fonction qui s’appelle elle-même
• La récursion terminale: L’appel récursif est la dernière instruction
Programmation Fonctionnelle
Concepts de base – Principe2: récursivité
La récursivité
Programmation Fonctionnelle
Concepts de base – Principe 3: ordre supérieur
• Tout comme en mathématiques, l’approche fonctionnelle
dans la programmation doit aussi permettre l’utilisation
des fonctions de différentes façons:
• Les fonctions sont des objets généraux du langage dont
l’utilisation ne comporte aucune restriction,
• Les fonctions peuvent être à leurs tours des valeurs,
• Les fonctions peuvent être traitées par d’autres fonctions
et être des paramètres d’autres fonctions (notion de
composition de fonctions en mathématiques)
Programmation Fonctionnelle
Concepts de base – Principe 3: ordre supérieur
• Fonction d’ordre supérieur: fonction en paramètre
• Dérivée: deriv ( f , x) = d f (x) / dx
• Application d’une fonction sur chaque élément d’une
collection:
• Ex: mapcar ( ‘(lambda(x) (* x x)) ‘(4 6 8)) dont l’évaluation
aboutit à (16 36 64)
• Composition de fonctions: f o g (x) = f(g(x))
• Avantages: généricité / réutilisabilité , extension du langage
Programmation Fonctionnelle
Concepts de base – Principe 4: déterminisme
• Indépendance / Déterminisme:
• f(x) = x + time () NON
• f(x,t)= x + t OUI
• Fonction = opération déclarative:
• Indépendante,
• Sans état interne,
• Déterministe
Une fonction retourne toujours la même valeur pourvu qu’on lui fournisse
les mêmes paramètres
Programmation Fonctionnelle
Concepts de base – Principe 4: déterminisme
Programmation en C:
Programmation en Lisp:
int n = 2;
(defun inc(n k)
int inc(int k)
« incrémentation sans
{ /* incrémentation par
effet de bord »
effet de bord */
(+ n k))
n = n + k;
return n;
(+ (inc 2 1)(inc 2 1))
}
f(inc(1) + inc(1)); Le 1er appel de la fonction inc
renvoie la même valeur que le
Le 1er appel de la fonction inc ne second appel
renvoie pas la même valeur que
le second appel
Programmation Fonctionnelle
Concepts de base – Principe 4: déterminisme
• Propriété de l’immuabilité: réduit les effets de bord & améliore l’approche concurrente:
une variable (fonctionnelle) est équivalente à:
• variable (mathématique)
• constante (impératif)
• final (Java)
• Flot de contrôle non linéaire: si aucune dépendance ne les lie, deux fonctions peuvent
être appelées dans n’importe quel ordre,
• Evaluation retardée: selon le besoin
• Garbage collector: ramasse miette au niveau de la mémoire
• Inférence de type: Déterminer automatiquement le type d'une expression ou d'une
fonction
Programmation Fonctionnelle
Concepts de base – Principe 4: déterminisme
• Les langages de programmation fonctionnelle « pures » (Miranda, Haskell) et les
programmes fonctionnels doivent avoir les qualités suivantes:
1. Tous les programmes et les procédures sont des fonctions et distinguent
clairement les valeurs en entrée « paramètres » et les valeurs à la sortie « résultats
»,
2. Il n’y a pas de variables, ni d’affectations; les variables sont remplacées par les
paramètres,
3. Il n’y a pas de boucles; les boucles sont remplacées par les appels récursifs,
4. La valeur résultat d’une fonction dépend seulement de la valeur de ses
paramètres et non de l’ordre des évaluations ou du chemin qui a mené à l’appel
de la fonction,
5. Les fonctions peuvent être vues comme des valeurs qui peuvent être traitées par
d’autres fonctions et jouer le rôle de paramètres de fonctions,
Programmation Fonctionnelle
Concepts de base – Principe 4: déterminisme
Par exemple:
(* (+ 2 3) (* 4 (+ 4 6)))
1er 2nd
paramètre paramètre
Fonction * de la de la
fonction * fonction *
(+ 2 3)
1er 2nd
paramètre paramètre
de la de la
fonction + fonction +
Fonction +
Programmation Fonctionnelle
Concepts de base – Principe 5: listes
• Liste vide : [ ] dans Haskell, ( ) dans Lisp
• Ajouter un élément en tête de liste:
• Haskell Lisp
• 1 : [] == [1] (cons 1 ()) == (1)
• 1 : [2 , 3] == [1, 2, 3] (cons 1 ‘(2 3)) == (1 2 3)
• [Link][] == [1,2,3] (cons 1 (cons 2 (cons 3 ()))) == (1 2 3)
• Récupérer la tête d’une liste:
• head [1,2] == 1 (car ‘(1 2)) == 1
• Récupérer la queue:
• tail [1,2] == [2] (cdr ‘(1 2)) == (2)
Programmation Fonctionnelle
Avantages
• Les langages dits purement fonctionnels n'autorisent pas la
programmation impérative. De fait, ils sont dénués d'effets de bord et
protégés contre les problèmes que pose l’exécution concurrente:
parallélisation facile des programmes fonctionnels
• Les langages fonctionnels ont comme autre propriété la transparence
référentielle. Il s’agit du principe selon lequel le résultat du programme
ne change pas si on remplace une expression par une expression
de valeur égale.
• La programmation fonctionnelle se prête mieux à l’application de façon
automatique des preuves de fonctionnement.
• Les programmes fonctionnels sont beaucoup plus robustes et plus
facilement maintenables,
Programmation
fonctionnelle
Fondements théoriques
Le λ-calcul
• Théorie des fonctions d'Alonzo Church (1930), comme
modèle universel de calcul, directeur de thèse d'Alan
Turing (machines de Turing, théorie de la calculabilité).
• peut encoder n’importe quel calcul (équivalent à machine
de Turing)
• est à la base des langages fonctionnels (Lisp, ML,
Haskell, Scheme)
• récemment est présent dans la plupart des langages de
programmation (Java, Phyton, javascript, c#,…)
Le λ-calcul
• Syntaxe
• Variables : x, y, … sont des λ-termes
• Applications (d’une fonction) : si u et v sont des λ-termes
uv est aussi un λ-terme. On peut alors voir u comme une
fonction et v comme un argument, uv étant alors l'image
de v par la fonction u.
• Abstractions lambda (fonction) : si x est une variable et u
un λ-terme alors λx.u est un λ-terme. Intuitivement, λx.u
est la fonction qui à la variable ou paramètre x associe ou
retourne une expression u. (unary anonymous fonction)
Le λ-calcul
• syntaxe
expression ::= variable identifiant
| expression expression application d’une fct
| λ variable . expression abstraction d’une fct
| ( expression) groupement
Le λ-calcul
• Variables
• x
• une occurrence de variable est dite muette ou liée si
elle apparaît dans le corps d'un λ-terme dont elle est
paramètre, sinon elle est dite libre.
Le λ-calcul
• Variables
• Ainsi, les variables libres d'une expression sont définies par :
• si x ∈ alors libres(x) = {x},
• libres(λx u) = libres(u) - {x},
• libres(uv) = libres(u) ∪ libres(v)
• Une variable ayant une occurrence non libre dans une expression est dite liée
dans cette expression.
• Une variable qui n’a pas d’occurrence dans une expression, elle n’est ni libre, ni
liée.
• Une expression est dite close si elle n'a pas de variable libre.
Le λ-calcul
• Variables liées et libres:
• Exemples:
• (a) libres (λx x) = libres(x) - {x} = {x} - {x} = {}, x est lié dans
(λx x)
• (b) libres(λx y) = libres(y) - {x} = {y} - {x} = {y}, y est libre
dans (λx y), x est lié
• (c) libres(λx (λy (x + y)) = libres((λy (x + y)) - {x} = libres (( x
+ y))- {y} - {x} = {x,y} - {y} - {x} = {} , x et y sont liés (λx (λy (x
+ y))
Le λ-calcul
• Applications
• fu
• appliquer la fonction f à son argument u
• f u v appliquer f à ses deux arguments -> appliquer f à u
donne une fonction qu’on applique à v.
• ((f u) v)
• Les applications sont faites de gauche à droite en l'absence
de parenthèses
Le λ-calcul
Abstractions
paramètre/variable
signifiant de
Fonction
λa.b expression retournée
abstraction lambda
Fonction anonyme unaire
Le λ-calcul
• Exemples :
• Constante : λx.y
• Identité : λx.x
• Fonction renvoyant une fonction : λx.(λy.a)
• Application : xyz ou ((xy)z)
• Fonctions à plusieurs arguments : λxy.a (λx.λy.a)
Remarques: les applications sont faites de gauche à droite en
l'absence de parenthèses.
Le λ-calcul
substitution
• Cette opération permet de remplacer les occurrences d'une variable par
un terme pour réaliser le calcul des λ-termes. On note t[x := u] la
substitution dans un lambda terme t de toutes les occurrences d'une
variable x par un terme u.
• Définition
• Variable: si t est une variable alors t[x := u] = u si x = t et t sinon
• Application: si t = vw alors t[x := u] = v[x := u]w[x := u] si v et w sont
des termes.
• Abstraction: si t = λy.v alors t[x := u] = λy.(v[x := u]) si x ≠ y et y n’est
pas une variable libre de u. Si y est une variable libre de u, on
renomme y avant de substituer. Si x = y le résultat est t.
Le λ-calcul
substitution
• Exemple: Dans ces exemples, les symboles x; y; z; a sont des variables.
• Dans une application : xyz[y := a] = xaz; x y [y:=λz.x ]= x (λz.x)
• Dans une abstraction (cas normal) : λ[Link][y := a] = λ[Link]
• Capture de variable libre : λx.x y[y := ax] = λ[Link](et non λ[Link]), renommage de
la variable liée
• λx.x y [y:=λz. x] = λ t. t (λz. x)
• λx.z(λ[Link]) [z:=λ[Link]] = λx.(λ[Link])(λt.(λ[Link])t)
• Substitution inopérante (sur variable liée): λ[Link][x := z] = λ[Link] = λ[Link]
!77
Le λ-calcul
β-réduction
• On appelle redex un terme de la forme (λx.u)v.
• On définit alors la β-réduction
(λx.u)v —> u[x := v]
• La réduction du terme (λx.u)v est la valeur de la fonction λx.u appliquée à la
variable v.
• u est l'image de x par la fonction (λx.u),
• L'image de v est obtenue en substituant dans u, x par v.
• Exemples
• (λ[Link])a donne xy[x := a] = ay
• (λx.y)a donne y[x := a] = y
Le λ-calcul
β-réduction
• Exemple
((λa.a) λb.λc.b)(x)λe.f
= (λb.λc.b) (x) λe.f
= (λc.x) λe.f
= x
β- Normal form
Le λ-calcul
la normalisation
• Un lambda-terme t est dit en forme normale si aucune β-réduction ne peut lui être
appliquée, c'est-a-dire si t ne contient aucun redex.
• Différentes stratégies de réduction sont définies dans le λ-calcul : stratégie applicative
(par valeur, dans les langages lisp et scheme), stratégie paresseuse (par nom, dans
Haskell).
• l'ordre d'évaluation des arguments d'une fonction n’a pas d'influence sur le résultat.
• Exemple
• Les symboles x; y; z; a sont des variables. Soit le terme (λx.y)((λ[Link])a)
• Strategie applicative : (λx.y) ((λ[Link]) a) —> (λx.y) aa —> y
• Strategie paresseuse : (λx.y) ((λ[Link]) a) —> y
Le λ-calcul
la normalisation
• Le processus de β-réduction est un processus qui est
non-déterministe == plusieurs possibilités peuvent s’offrir
sur la façon de choisir les termes sur lesquelles on
souhaite opérer la β-réduction
• La question est de savoir si le choix qu’on peut faire influe
sur la terminaison de la réduction ou sur la forme
normale.
• On démontre que la forme normale ne dépend pas du
choix, par contre la terminaison dépend du choix fait sur
les possibilités de réduction.
Le λ-calcul
combinator
• une lambda fonction qui n’a pas de variable libre
• λb.b combinator
• λb.a not combinator
• λab.a combinator
• λ[Link] not combinator
Le λ-calcul
combinator
• exemples
• λa.a identité
• λf.ff auto application
• λab.a premier
• λab.b second
Le λ-calcul
λ TM
Le λ-calcul
Tout peut être une Fonction
Le λ-calcul
combinator
• Pour compléter cette modélisation pour un langage de
programmation minimal, on définie les fonctions
incrémentation, décrémentation, addition, soustraction,
les opérateurs booléens et les valeurs booléennes,
• On définie de même la récursivité,
Le λ-calcul
Booléens
T : true λab.a VRAI
F: false λab.b FAUX
not λ[Link] Négation
and λ[Link] conjonction
or λ[Link] Disjonction
if λ[Link] if
and true false= λ[Link] true false = true false true = λpq.p false true = false.
if true p q = λ[Link] true p q = true p q = λab.a p q = p
Le λ-calcul
Récursivité
• Y combinator
Y= λt. (λx.t(x x)) (λx.t(x x))
• Yf = λt. (λx.t(x x)) (λx.t(x x)) f = (λx.f(x x)) (λx.f(x x)) = f
((λx.f(x x)) (λx.f(x x))) = f(Y f)
• Tf = f(Yf) = f(f(Yf)) = f(f(f(Yf))) = ….
Le λ-calcul
Récursivité
• T = λf.λ[Link](= n 1) 1 (* n f (- n 1))
• (YT) 2 = T (YT) 2 = if (= 2 1) 1 (* 2 (YT (- 2 1))) = (* 2 (YT
1)) = (2 * 1) = 2
• (YT)1 = T (YT) 1 = if (= 1 1) 1 (0 1 (Y T(- 1 1))) = 1
Programmation Fonctionnelle
notion d’expression symbolique et types
• En Lisp,
• objects de base : sortes de mots appelés atomes,
• un objet auto-évaluant,
• ou un symbole
• Une expression (en anglais form) Common Lisp peut être :
• un atome
• ou une expression composée (avec des parenthèses).
Programmation Fonctionnelle
notion d’expression symbolique et types
• Les programmes et les données sont exprimés à l’aide de la même
syntaxe « s-expressions » « expressions symboliques »:
• L’application de fonctions et les instructions conditionnelles sont écrites
comme des listes, entre parenthèses, avec le nom de l’instruction
comme préfixe, ex:
(+ 2 3) (cons a (b c )) ….
• Le programme et les données sont distinguées selon le contexte.
• Cette uniformité des données et du programme permettent une grande
flexibilité et une haute expressivité:
• Les programmes peuvent être manipulés comme des données.
Programmation Fonctionnelle
notion d’expression symbolique et types
• Les structures de données simples:
• Symboles:
• Ce sont des “mots” qui ne sont pas des nombres. Ils ne peuvent
contenir les caractères spéciaux suivants : ( ) [ ] { } ; , " ’ ‘ # /
• un symbole est généralement utilisé comme variable, son type est
implicite dépendant de sa valeur. Sa valeur est l’objet qui lui est lié (s’il
existe), par exemple: (setq pi 3.14159)
• Atomes:
• Chaines de caractères, exemple: enit ;
• nombres, entiers ou flottants, exemples: 2 , 2.3, ..
• Les atomes sont des s-expressions dont leurs valeurs sont identiques à
eux mêmes (auto-évaluant)
Programmation Fonctionnelle
notion d’expression symbolique et types
• Les Structures de Données Composées: les listes
• Le format général d’une liste:
(E1 E2 ...... En) où Ei est une S-expression.
• Dépendamment du contexte, une liste peut être traitée littéralement:
• comme une donnée:
‘((révolution Tunisie) (anniversaire "14 janvier 2017"))
• comme une application de fonction avec les paramètres passés par
valeur:
(append x y)
( + 3 5)
Programmation Fonctionnelle
notion d’expression symbolique et types
• Les Structures de Données Composées: les listes
• Une liste est une suite d’objets séparés par des blancs
et entourée d’une paire de parenthèses (le nombre
d’objets est la longueur de la liste).
• Une liste (E1 E2 ...... En) est produite par cons:
(cons E1 (cons E2 ... (cons En ()) ... ))
E1 E2 En
Programmation Fonctionnelle
notion d’expression symbolique et types
• Les listes et l’accès à leurs éléments:
• Les listes sont définies récursivement:
Une liste vide: (), (c’est aussi un atome)
Une liste non-vide: (cons ‘a L) où L est un symbole dont la valeur
est une liste.
• La tête et la queue d’une liste:
(car (cons ‘a L)) retourne a
(cdr (cons ‘a x)) retourne x
(car ()) et (cdr ()): paramètre invalide
Programmation Fonctionnelle
notion d’expression symbolique et types
• Les listes et l’accès à leurs éléments:
• Une convention de notation pour accéder aux autres éléments de la liste:
(caar x) (car (car x))
(cdadr x) (cdr (car (cdr x))))
• Par exemple, l’évaluation suivante se fait en 4 étapes:
(caadar '((p ((q r) s) u) (v)))
(caadr '(p ((q r) s) u))
(caar '(((q r) s) u))
(car '((q r) s))
(q r)
• Le deuxième élément d’une liste x — s’il existe:
(cadr x)
• Le troisième, quatrième, ... :
(caddr x), (cadddr x), ...
Programmation Fonctionnelle
notion d’expression symbolique et types
Construction : cons, list, list*, append, copy-list, copy-tree, revappend,
butlast, ldiff, subst, subst-if, subst-if-not,adjoin, union, intersection, set-
difference, set-exclusive-or, subsetp
Acc`es : car, cdr, member, nth, nthcdr, last, butlast, cadadr, cdaaar, . . .
first, second, . . ., tenth
Autres : length, subseq, copy-seq, count, reverse, concatenate, position,
find, merge, map, some, every, notany, notevery,search, remove, remove-
duplicates, elt, substitute, mismatch
Programmation Fonctionnelle
Règles d’évaluation
• Lisp est utilisé de façon interactive :
• Aucun programme principal,
• L’interpréteur est une boucle Read-Eval-Print. Il lit une s-expression e, l’évalue
et imprime sa valeur v (e) (ou un message spécifique).Il peut aussi lire une
“définition” et l’enregistrer.
• Un programme Lisp est une collection de fonctions qui peuvent être invoquées
directement ou indirectement par l’interpréteur.
• L’évaluation est une fonction récursive. L’évaluation d’une s-expression peut
requérir l’évaluation de sous-expressions.
• Toute s-expression est évaluée: Il faut dire explicitement à Lisp de ne pas
évaluer quelque chose (avec la fonction quote ou ‘ )
• Les symboles et les atomes sont des cas d’évaluation de base. Les autres s-
expressions constituent des cas inductifs.
Programmation Fonctionnelle
Règles d’évaluation
• Une expression tapée à la boucle d’interaction est
d’abord
• lue et analysée syntaxiquement.
• Le résultat de cette analyse est une représentation interne
de l’expression (S-expression).
• La fonction responsable de cette analyse s’appelle read.
• Cette fonction est disponible à l’utilisateur.
Programmation Fonctionnelle
Règles d’évaluation
• La S-expression est ensuite évaluée, c’est à dire que sa
valeur est calculée.
• Cette évaluation peut donner des effets de bord.
• Le résultat de l’évaluation est un ou plusieurs objets Lisp.
• La fonction responsable de l’évaluation de S-expressions
s’appelle eval.
• Cette fonction est disponible à l’utilisateur.
Programmation Fonctionnelle
Règles d’évaluation
• Les objets résultant de l’évaluation sont ensuite affichés
(ou imprimés) en représentation externe.
• La fonction responsable de l’affichage s’appelle print.
• Cette fonction est disponible à l’utilisateur.
Programmation Fonctionnelle
Règles d’évaluation
• Les cas d’évaluation de base :
• Les atomes, comme les nombres et les chaînes de caractères,
s’évaluent à eux mêmes, ex: 2, ‘‘a’’ », 0, nil, (), T
• Les symboles sont évalués en fonction de l’environnement
courant et remplacés par leurs valeurs (état dynamique de
l’environnement),
• La liste vide () est évaluée à elle-même car elle a le double
statut de liste vide et d’atome, aussi noté nil. Elle représente
aussi la valeur booléenne false.
• L’évaluation d’un booléen donne ce booléen. La valeur
booléenne true est représentée par T (ou #t dans certains
dialectes et #f ou nil la valeur booléenne false).
Programmation Fonctionnelle
Règles d’évaluation
• Expressions composées
• Une expression composée est une liste de sous-
expressions entourées de parenthèses : (op e1 e2 ... en)
• Le plus souvent, la première sous-expression est un
symbole
• qui est le nom d’une fonction, d’une macro ou d’un
opérateur spécial.
• Les autres sous-expressions sont les arguments de la
fonction, de la macro ou de l’opérateur spécial.
Programmation Fonctionnelle
Règles d’évaluation
• Les cas d’évaluation de base (fonction) :
• L’expression à évaluer est une liste (e0 ... en).
• La parenthèse ouverte est la marque du cas inductif.
• Cas des combinaisons:
• 1. Les ei sont évalués (soient vi les valeurs) ; v0 doit
être une fonction dont le domaine contient (v1, . . . ,
vn).
• 2. La fonction v0 est appliquée à (v1, . . . , vn).
• 3. Le résultat est affiché.
Programmation Fonctionnelle
Règles d’évaluation
• Cas des formes spéciales:
• La syntaxe est celle d’une combinaison, mais chaque
forme spéciale a sa propre règle d’évaluation.
• Les formes spéciales sont identifiées par un mot-clef,
qui est le premier élément de l’expression à évaluer;
Programmation Fonctionnelle
Règles d’évaluation
CL-USER> (+ 3 4)
CL-USER> (length "hello")
CL-USER> (+ (* 3 4 2) (- 5 4) (/ 5 3))
80/3
CL-USER> (if (> 5 4) "oui" "non")
"oui"
CL-USER> (length ‘(1 2 3 4))
CL-USER> (floor 10.3)
10
0.3000002
Ici, if est un opérateur spécial, alors que +, *, -, /, >,
length sont des fonctions.
Programmation Fonctionnelle
Règles d’évaluation
• Exemple d’évaluation d’une s-expression de type combinaison :
(+ (* 3 -2) (- 5 3))
Fonction addition v((* 3 -2)) = -6 v((- 5 3)) = 2
-4
Programmation Fonctionnelle
Règles d’évaluation
• Exemple d’évaluation d’une s-expression de type combinaison :
(cons (cons 3 ()) (cons 5 (cons 4 ())))
Fonction cons v((cons 3 ())) = (3) v((cons 5 (cons 4 ())) =
(cons v(5) v((cons 4 ())))=
((3) 5 4)
Programmation Fonctionnelle
Règles d’évaluation
• Autres formes spéciales:
• La fonction Quote ou ‘:
• La fonction quote bloque le processus systématique d’évaluation:
(quote pi) ou de façon équivalente: 'pi
• La fonction setq:
(setq pi 3.141592) ou (setq x (+ 3 4))
• Exemples:
(* 2.0 pi) retourne 6.283184
(* 2.0 'pi) paramètre invalide
('* 2.0 'pi) fonction invalide
(write 'pi) affiche le symbole pi
(write pi) affiche 3.141592
Programmation Fonctionnelle
Règles d’évaluation
• Exemple d’évaluation d’une s-expression de type macro :
(and e1 ... en)
• Les ei sont évalués dans l’ordre et la première valeur
fausse est retournée ; les valeurs suivantes ne sont pas
calculées.
• S’il n’y a pas de valeurs fausses, la dernière valeur
calculée est retournée.
• S’il n’y a pas de valeurs du tout, T ou #t est retournée.
CL-USER> (and (= 2 2) (< 2 1) (/ 2 0) (+ 2 3))
NIL
Programmation Fonctionnelle
Règles d’évaluation
• La définition d’une macro est essentiellement une
fonction qui génère du code Lisp.
• Une fonction produit des résultats mais une macro
produit des expressions-qui lorsque évaluée produit des
résultats.
• exemple :
> (defmacro nil! (var) (list ’setq var nil))
NIL!
Programmation Fonctionnelle
Règles d’évaluation
• (nil! x) a le même effet que (setq x nil)
• l’expression (nil! var) est transformée en (setq var nil)
avant d’être évaluée.
• Deux étapes:
1. construire l’expression spécifiée par la définition de la
macro (macroexpansion)
2. évaluer l’expression à la place de l’appel de la macro
Programmation Fonctionnelle
Règles d’évaluation
• Autres formes spéciales:
• La forme lambda :
• La fonction qui à son unique argument associe le carré de sa valeur s’écrit λx .
mult x x
• en Lisp, elle s’écrit: (lambda (x) (* x x))
• La liste (x) est la liste des paramètres.
• La liste (* x x) est le corps de la forme lambda.
==> (lambda (x) (* x x))
:-) # lambda function
==> ((lambda (pi) (* pi pi)) 12)
:-) 144
==> ((lambda (car) (* car car)) 12)
:-) 144
==> x
:-) Error - unbound variable x
Programmation Fonctionnelle
Règles d’évaluation
• Exemples
( (lambda (x) (* 2 x))
( (lambda (x)
(- 9 ( (lambda (x) (+ 3 x)) x) ) ) x))
((lambda (w) (* 2 w))
((lambda (v)
(- 9 ((lambda (u) (+ 3 u)) v))) x))
Programmation Fonctionnelle
Porté, Réduction et Combinaison
==> (setq x 5)
:-) 5
• Les expressions qui suivent ont toutes pour valeur 2.
((lambda (x) (* 2 x)) ((lambda (x) (- 9 ((lambda (x) (+ 3 x)) x))) x))
(lambda (w) (* 2 w)) (lambda (v) (- 9 ((lambda (u) (+ 3 u)) v))) x))
(* 2 ((lambda (v) (- 9 ((lambda (u) (+ 3 u)) v))) x)) ((lambda (w) (* 2 w)) (- 9 ((lambda (u) (+ 3
u)) x)))
((lambda (w) (* 2 w)) ((lambda (v) (- 9 (+ 3 v))) x))
(* 2 (- 9 ((lambda (u) (+ 3 u)) x)))
(* 2 ((lambda (v) (- 9 (+ 3 v))) x))
((lambda (w) (* 2 w)) (- 9 (+ 3 x)))
(* 2 (- 9 (+ 3 x)))
Programmation Fonctionnelle
Occurrences libres et liées
• On retrouve les mêmes notions vues dans les fondements
théoriques avec le λ-calcul:
• Pour évaluer l’expression ((lambda (x) (+ x y)) 5) il est nécessaire
que y ait une valeur ; par contre, la valeur éventuelle de x est sans
importance.
• On peut d’ailleurs remplacer les deux occurrences de x par z, par
exemple.
• Même dans un environnement où y n’est pas lié, l’expression
(lambda (x) (+ x y)) a une “valeur potentielle”, mais cette valeur
(fonctionnelle) ne pourra être appliquée à un argument que dans
un environnement où y est lié.
Programmation Fonctionnelle
Occurrences libres et liées
• Soit une forme lambda du type (lambda (... x ...) E)
• Toute occurrence de x dans le corps E est dite liée.
• Par extension, une occurrence de x est liée dans une expression si cette
expression comporte une sous-expression (forme lambda) dans laquelle
l’occurrence en question est liée.
• Une occurrence non liée (en dehors d’une liste de paramètres) est libre.
• Dans l’expression
((lambda (x) (- 9 ((lambda (x) (+ 3 x)) x))) x)
les deux premières occurrences de x sont des paramètres, les troisième et
quatrième occurrences de x sont liées, la cinquième occurrence de x est libre.
Programmation Fonctionnelle
Arguments et valeurs des fonctionnelles
• Les fonctions, sont généralement des valeurs des formes lambda,
• On peut définir une fonctionnelle admettant d’autres
fonctionnelles comme arguments, et renvoyant une fonctionnelle
comme résultat.
• Pour pouvoir réutiliser une fonctionnelle, on lie la forme lambda
qui lui est associée à un symbole en utilisant « define » (ou
«defun» selon le langage utilisé)
• Ceci évoque les mathématiques mais contraste avec les langages
de programmation usuels, qui ne permettent généralement pas,
par exemple, de renvoyer une procédure comme résultat de
l’application d’une autre procédure à ses arguments.
Programmation Fonctionnelle
Arguments et valeurs des fonctionnelles
• La fonction de déclaration de fonction:
• La fonction defun (ou define) permet de déclarer des fonctions à introduire
dans l’environnement , de sorte qu’elles peuvent être appelées en
deuxième étape:
(defun puissance3 (x)
(* x x x))
function puissance3
—> (define puissance3(lambda (x) (* x x x)))
function puissance3
—> (puissance3 2)
8
Programmation Fonctionnelle
Récursivité et terminaison
• La récursivité est un des principes de base de la programmation
fonctionnelle,
• Le risque qui se pose avec la récursivité est l’engagement dans une
évaluation infinie, d’où se pose la question de la terminaison d’une forme
récursive,
• Exemples:
• (defun fact (n) (* n (fact (- n 1)))) qui ne termine jamais
• appel de fact avec argument négatif , ne termine jamais
• Une définition récursive d’une fonction doit comporter toujours une
condition d’arrêt de la récursivité,
Programmation Fonctionnelle
Récursivité et terminaison
• Exemple de la fonction fibonacci:
(define fib (n)
(if (< n 2) n (+ (fib (- n 1)) (fib (- n 2)))))
• Terminaison de (fib n) (n ∈ N) : pas de problème (démonstration par
récurrence).
• L’efficacité du calcul est inacceptable :
(fib 9)
(+ (fib 8) (fib 7))
(+ (+ (fib 7) (fib 6)) (fib 7))
...
Programmation Fonctionnelle
Récursivité et terminaison
• Version de Fibonacci plus efficace:
(defun fib_a (n a b)
(if (= n 0) a (fib_a (- n 1) b (+ a b))))
• Si n, a et b ont pour valeurs respectives n, fi et fi+1, alors
(fib_a n a b) a pour valeur fn+i. En particulier,
(fib_a n 0 1) a pour valeur fn.
Programmation Fonctionnelle
Récursivité et terminaison
• Principe de la récursivité structurelle
• Le système “accepte” toute définition récursive syntaxiquement
correcte, même si la procédure associée donne lieu à des calculs infinis.
• L’utilisateur doit savoir si, dans un domaine donné, le calcul se
terminera toujours.
• Pour les domaines usuels, des schémas existent qui garantissent la
terminaison.
• Cas particulier : les schémas structurels, basés sur la manière dont les
objets du domaine de calcul sont construits.
• Le processus d’évaluation réduit le calcul de f(v) au calcul de f(v1), . . . ,
f(vn) où les vi sont des composants (immédiats) de v.
Programmation Fonctionnelle
Récursivité et terminaison
• Cette technique est sûre tant que l’on se limite aux domaines dont les
objets ont un nombre fini de composants (immédiats ou non),
clairement identifiés.
• Domaines usuels de base : Nombres naturels, Listes, Expressions
symboliques.
• Conceptuellement, les naturels sont construits à partir de 0 et de la
fonction successeur:
• 0 n’a pas de composant (objet de base)
• 16 est le seul composant immédiat de 17=succ(16)
• Correspondance naturelle entre les listes et les arbres. Chaque nœud
de l’arbre a un nombre fini quelconque de fils.
Programmation Fonctionnelle
Fonctionnelles typiques
• La fonction let :
• La fonction let permet à des valeurs d’avoir des noms temporaires à
l’intérieur d’une s-expression:
> (let ((a 2) (b 3)) (+ a b))
5
• L’évaluation de cette s-expression se fait come suit:
• La première s-expression est une liste d’affectation, et les symboles
utilisés auront dans le reste des s-expressions de la liste les valeurs
associées,
• Le résultat de l’évaluation de la dernière s-expression est retourné
comme valeur retournée de la fonction let,
Programmation Fonctionnelle
Fonctionnelles typiques
• La fonction if :
• La fonction if permet une évaluation similaire à la construction if-then-else, ainsi que
la fonction cond:
(if <expr1> <expr2> <expr3>)
(cond (<expr1> <expr11>) (<expr2> <expr21>) …..(<exprn> <exprn1>))
(if (= a 0) if a = 0 then
0 return 0
(/ 1 a)) else return 1/a
(cond ((= a 0) 0) if a = 0 then retrurn 0
((= a 1) 1) elsif a = 1 then return 1
(T (/ 1 a))) else return 1/a
Programmation Fonctionnelle
Fonctionnelles typiques
DEFPARAMETER toujours affecte une
valeur:
[1]> (defparameter a 1)
SETF est une macro qui utilise SETQ, mais a
A
plus de possibilités. dans un sens il est un
opérateur d’affectation plus général E.g.
[2]> (defparameter a 2)
avec SETF:
> (defparameter c (list 1 2 3))
[3]> a
> (setf (car c) 42)
2
42
> c
DEFVAR affecte la valeur 1 seule fois:
(42 2 3)
[4]> (defvar b 1)
• mais avec SETQ:
[5]> (defvar b 2)
• [> (setq (car c) 42)
B
*** - SETQ: (CAR C) is not a symbol
[6]> b
Programmation Fonctionnelle
Principales Problématiques
• L’évaluation retardée:
• Dans l’expression (if a b c) l’évaluation de b et c est retardée jusqu’à ce que a soit
évaluée et en fonction du résultat b ou c sera évaluée. Ceci explique pourquoi
cette fonction ne peut être écrite comme fonction par l’utilisateur,
• La prise en compte de ce type de processus diffère d’un L.F. à un autre et peut
rendre plus complexe la sémantique du langage,
• La gestion dynamique de la mémoire:
• Un système de gestion de la mémoire par pile, n’est pas adapté, car la référence
à des environnements locaux de fonctions peut persister même après avoir quitté
la fonction.
• Une solution consiste en l’interdiction de la désallocation de la mémoire, avec la
mise en place d’un système de « garbage collector »
Programmation logique
• Programmation logique
a- Introduction
b- fondements théoriques : rappel sur le calcul des prédicats
c – concepts de base
d- Unification
e- Principe de Résolution
f- Principe de recherche de solutions : approche non déterministe et
déterministe
g- Hypothèse du monde clos
Programmation logique
• Définition d’un langage de programmation logique:
• Un L.P. logique est un système de notation permettant d’écrire des déclarations
logiques et des algorithmes spécifiés pour implémenter les règles d’inférences.
• Ensemble des déclarations logiques = axiomes = programme logique,
• Ensemble des déclarations dérivables = théorèmes = entrées ou requêtes
ou buts
• Dans un système de programmation logique « pure » rien n’ai dit sur la façon
dont certaines déclarations doivent être dérivées. Le chemin pour y arriver ou
les étapes pour y parvenir, qu’un système automatique de déduction choisit,
relève de la partie contrôle d’un système de programmation logique.
• Paradigme de la programmation logique établi par Kowalski:
Algorithme = logique + contrôle
Programmation Logique
Naissance
• La logique comme science du raisonnement et de la preuve a existé
depuis le temps des philosophes Grecs,
• La logique symbolique comme théorie mathématique de la preuve a
démarré avec les travaux de G. BOOLE et A. De Morgan au milieu des
années 1800,
• Les déclarations logiques, ou des formes restreintes de ces
déclarations, sont vues comme un L.P. et exécutées par un ordinateur
à travers un système d’interprétation: travail réalisé par Robinson,
Colmerauer et Kowalski, a donné naissance au L.P. Prolog, dans les
années 1970s,
• Ces travaux ont conduit à la naissance d’autres L.P. logiques,
notamment des langages à base d’équation,
Programmation Logique
Naissance
Programmation Logique
Fondements Théoriques
• Rappel de logique Mathématique / Formelle:
• Le Calcul des Prédicats du 1er ordre présente la difficulté de:
• offrir une multitude de façons différentes pour exprimer les mêmes déclarations,
• Proposer plusieurs règles d’inférence,
• Par conséquent, la plupart des L.P. Logiques ont fait le choix de se restreindre à un sous-ensemble du Calcul des
Prédicats du 1er ordre:
• Utiliser seulement des Clauses de Horn
• Utiliser une seule règle d’inférence: Le Principe de Résolution
• Une Clause de Horn est une expression de la forme:
• a1⋀ a2 ⋀ a3 . . . ⋀ an → b les ai et b sont des prédicats
• Ceci signifie: b est vraie si tous les ai sont vrais, s’écrit aussi: b ← a1 ⋀ a2 ⋀ a3 . . . ⋀ an
• La clause sans queue: b ← veut dire que b est toujours vrai (formellement c’est un axiome, ou une
affirmation)
• La clause sans tête: ← a1 ⋀ a2 ⋀ a3 . . . ⋀ an représente une séquence de questions à vérifier,
Programmation Logique
Fondements Théoriques
• Rappel de logique Mathématique / Formelle:
• La transformation d’une formule du Calcul des Prédicats du 1er
ordre en une Clause de Horn, nécessite plusieurs étapes
(élimination des connecteurs autres que ⋀ et, → la
Skolémisation, élimination des quantificateurs, …) (voir cours
Logique Formelle ou Logique Mathématique);
• Exemple de passage vers une description sous forme de Clause de
Horn:
• Le pgcd de 2 entiers positifs u et v se définie par:
• Le pgcd de u et 0 est u.
• Le pgcd de u et v, si v n’est pas 0, est le même que le pgcd de v
et le reste de la division de u par v
Programmation Logique
Fondements Théoriques
• Rappel de logique Mathématique / Formelle:
• Traduction en Prédicats du 1er ordre:
• ∀u, pgcd(u, 0, u).
• ∀u, ∀v, ∀w, ¬ zero(v) ⋀ pgcd(v, mod(u, v), w) → pgcd(u,
v, w)
• Formulation sous forme de Clause de Horn:
• → pgcd(u, 0, u)
• ¬ zero(v) ⋀ pgcd(v, mod(u, v), w) → pgcd(u, v, w)
• Autre Exemple:
• ∀ x, y, z, x est le grandparent de z si x est parent y qui est parent de
z
• parent(x, y) ⋀ parent(y,z) → grandparent(x,z)
Programmation Logique
Fondements Théoriques
• Rappel de logique Mathématique / formelle:
• L’énoncé formel du principe de Résolution: (voir cours de logique formelle ou logique mathématique) :
• La mise en œuvre du Principe de Résolution sur des Clauses de Horn se présente comme suit:
Soient 2 clauses de Horn:
a ← a1 , a2 , a3 . . . , an.
b ← b1 , b2 , b3 . . . , bm.
Si bi peut être mis en correspondance (unifié ) avec a, il est possible d’inférer une nouvelle clause de Horn
de la forme
b ← b1 , b2 , b3 . . bi-1 , a1 , a2 , a3 . . . , an , bi+1 . . ., bm
Ce processus est poursuivi jusqu’à ce qu’éventuellement une clause de Horn vide soit produite. Si tel est le
cas, alors nous avons une preuve de la déclaration originelle.
Programmation Logique
Concepts de Base
• Écrire un programme en Prolog consiste essentiellement à définir un ensemble d'entités et des relations
entre ces entités.
• Pour se référer à une entité, on utilise des termes. Un terme est une constante, une variable ou un
terme composé :
• Terme Constante :
• Désigne une entité du monde.
• Tout identificateur qui commence par une lettre minuscule est une constante.
• Si on veut utiliser une constante qui commence par une lettre majuscule, il faudra la délimiter par
des apostrophes, Exemples : ali, 3, ‘ENIT'.
• Terme Variable :
• sert à désigner une entité inconnue mais qui existe.
• Aussitôt que cette entité devient connue (on dira alors que la variable est instanciée), elle sera
toujours associée à celle-ci (au sein de la même formule).
• Tout identificateur qui commence par une lettre majuscule. Une variable peut aussi commencer par
le symbole ‘_ ‘ (il s'agira alors d'une variable anonyme).
Programmation Logique
Concepts de Base
• Pour se référer à une relation, on utilise des prédicats.
• Un prédicat est une expression qui retourne une valeur de vérité quand
elle est appliquée à certains arguments (les arguments d'un prédicat sont
des termes)
• Un prédicat avec un seul argument représente une propriété, ex: grand-
de-taille (ali)
• Si un prédicat a plus d'un argument, il exprime une relation entre des
entités du monde, ex: on peut écrire une expression mere(fatma, ali) pour
indiquer que fatma est la mère de ali, ou que ali est la mère de fatma.
C’est au programmeur de se donner une convention et de la respecter
dans tout le programme,
• L'argument d'un prédicat peut être n'importe quel terme. Il peut être un
terme composé, ou simple comme une constante ou une variable.
Programmation Logique
Concepts de Base
• Un prédicat appliqué à des arguments représente une relation entre des entités du monde qui
peut être vraie ou fausse .
• Comment fait-on pour déterminer cette valeur de vérité?
• Une façon simple de le faire est de le déclarer, ou de l’affirmer, en l’exprimant comme un fait
de Prolog:
• Pour affirmer que fatma est la mère de ali, on le déclare ainsi:
mere (fatma, ali).
• Si on a plusieurs déclarations/affirmations, on les définie comme un ensemble de faits:
homme(ali).
homme(mohamed).
femme(fatma).
mere(fatma, ali).
pere(mohamed, ali).
Programmation Logique
Concepts de Base
• Requêtes:
• Pour utiliser ces faits (ce programme), il faut poser des questions à Prolog, à travers la
formulation d’une requête.
• Une requête est une expression prédicative entrée après l'invite ?- . Prolog y répondra par YES si
elle est vraie, et NO dans le cas contraire.
• Pour vérifier si fatma est une femme:
?- femme(fatma).
Yes
• On peut aussi exprimer une requête en utilisant un argument de type variable:
?- femme(X).
X= fatma
Yes
• Comment fait Prolog pour répondre à ce type de questions? Substitution et Instance
Programmation Logique
Concepts de Base
• Substitution:
• Une substitution θ est un ensemble fini (éventuellement vide) de paires de la forme Xi =
ti, où Xi est une variable et ti est un terme, qui respecte les contraintes suivantes :
- Pour tout Xi = ti ∈ θ et Xj = tj ∈ θ, où i ≠ j, on ne peut pas avoir Xi = Xj .
- Soit Xi = ti ∈ θ . Pour tout Xj = tj ∈ θ , Xi ne peut pas apparaître dans tj .
• Exemples / Contre exemples:
• Les ensembles {X = ali, Y = 2} et {X = fatma, Y = f(Z)} sont des substitutions
• L'ensemble {X = ali, Z = f(X)} n'est pas une substitution légale, parce que la variable
X ne peut pas apparaître dans un autre terme.
• L'ensemble {X = ali, Y = 2, X = fatma} n'est pas une substitution parce que X
apparaît deux fois à gauche du signe =.
• L’ensemble {X = p(Z), Y = Z} est une substitution valide.
Programmation Logique
Concepts de Base
• Substitution (suite):
• Une substitution s’applique généralement à un terme composé ou une
expression prédicative A;
• L’effet de θ sur A, noté θ A est comme suit:
• pour toute variable X présente dans A, on remplace toutes les
occurrences de celle-ci par le terme t qui lui est associé dans θ
• Exemple:
• la substitution θ = {X = ali, Y = 2}, appliquée à l'expression p(X,f(Z),Y),
produit une nouvelle expression p(ali,f(Z),2)
• θ = {X = ali, Y= 2} appliquée à A = p(X,X,fatma), donne: p(ali,ali,fatma)
Programmation Logique
Concepts de Base
• Instance:
• Une expression A est une instance d'une autre expression
B s'il existe une substitution θ telle que A = θ B.
• Par exemple:
• A = p(ali,Y) est une instance de B = p(X,Y), car A = θ B,
avec θ = {X=ali}
• p(ali,fatma) est une instance de p(X,Y) avec θ = {X=ali,
Y= fatma}
Programmation Logique
Concepts de Base
• Requêtes (suite):
• Reprenons notre programme (un ensemble de faits):
homme(ali).
homme(mohamed).
femme(fatma).
mere(fatma, ali).
pere(mohamed, ali).
• Une réponse à une requête en utilisant un ou plusieurs arguments de type variable, est une substitution
de toutes les variables apparaissant dans la requête:
?- homme(X).
X= ali 1ère substitution
X= mohamed 2ème substitution
Yes
• Ou encore:
?- pere(X,Y), femme(Y).
No Pas de substitution
Programmation Logique
Concepts de Base
• Clauses:
• Si un programme Prolog se limitait à un ensemble de faits, Prolog
n’aurait aucune utilité,
• On doit pouvoir déterminer une relation entre deux entités de façon
indirecte, par exemple pour exprimer le fait que:
une personne est propriétaire d’un objet si elle l’a acheté
• Pour ce faire, on utilise une clause pour le dire et définir un prédicat en
fonction d’autres prédicats:
proprietaire (X,Y):- acheter(X,Y).
ceci se comprend comme suit:
pour savoir si X est le propriétaire de Y, il faut vérifier si X a acheté Y
Programmation Logique
Concepts de Base
• Clauses (suite):
• Notre programme peut être complété comme suit:
proprietaire(X,Y):- acheter(X,Y).
proprietaire(X,Y):- recevoir(X,Y).
acheter(fatma,manteau).
recevoir(ali,auto).
• Requête:
?- proprietaire(X,Y).
X = fatma; Y = manteau
X = ali ; Y = auto
Yes
Programmation Logique
Unification
• Approche intuitive:
• Intuitivement, l'unification consiste en une tentative pour déterminer s'il
existe une manière d'instancier deux expressions afin de les rendre égales.
• Plus formellement, l'unification de deux termes A et B est une substitution
telle que
θ A = B. On dénote θ l'unificateur de A et B.
• Par exemple, la substitution {Y = ali, X = voiture-de(ali)} est un unificateur
des énoncés :
nettoie(ali,X) et nettoie(Y,voiture-de(Y))
• En Prolog, l’opérateur ‘=‘ signifie l’unification
Programmation Logique
Unification
• Unificateur le Plus Général d’un ensemble d’expressions
E, est un unificateur g de E (s’il existe) tel que pour tout
unificateur S de E il existe un autre unificateur S’ tel que
E S = E g S’.
• Exemple : E1 = Y E2 = f(X)
• Unificateur le plus général : {f(X)/Y}
Programmation Logique
Unification
• Approche intuitive:
• Quand Prolog tente d’unifier un but (une requête ) avec un fait ou la tête d’une
clause, il peut être amener à renommer les variables:
nettoie (ali, X)
?- nettoie(X, voiture-de(ali))
• la variable X du fait n’a rien à voir avec la variable X de la requête et donc Prolog
procède implicitement à une re-nomination des variables comme suit:
nettoie (ali, X)
?- nettoie(X1, voiture-de(ali))
• L’unification devient alors possible avec:
{X = voiture-de(ali), X1=ali}
Programmation Logique
Unification
• Approche intuitive:
• Prolog tente systématiquement de trouver l’unificateur le plus général, c’est-à-
dire celui qui n’instancie une variable que si c’est vraiment nécessaire pour
obtenir un unificateur:
nettoie(ali,X) = nettoie(Y,Z)
{ Y = ali, X = Z }
ou
{ Y = ali, X = Z, W = mohamed }
ou
{ Y = ali, X = voiture-de(ali), Z = voiture-de(ali) }
ou
...
Programmation Logique
Unification
• Algorithme d’Unification : algorithme intuitif
• Intuitivement, deux expressions prédicatives A et B s'unifient si elles sont formées à partir d'un même
prédicat, avec le même nombre d'arguments.
• Chaque argument du prédicat de A doit s'unifier avec l'argument à la même position dans B.
• Chaque argument est lui-même un terme, qui peut être une variable, une constante ou un terme
composé.
• Deux termes s'unifient si une des trois conditions suivantes est respectée :
1- Les deux termes sont des constantes identiques.
2- Un des termes est une variable non instanciée. Dans ce cas la variable sera
instanciée par l'autre terme (si ce terme ne contient pas la variable en question).
3- Les deux termes respectent les conditions suivantes :
- Ils ont le même foncteur et le même nombre d'arguments.
- Les arguments s’unifient.
Programmation Logique
Unification
function unify(E1, E2)
begin
case
both E1 and E2 are constants or the empty list:
if (E1 = E2)
then return {}
else return FAIL;
E1 is a variable:
if (E1 occurs in E2)
then return FAIL
else return {E2 / E1};
E2 is a variable:
if (E2 occurs in E1)
then return FAIL
else return {E1 / E2};
either E1 or E2 is the empty list: return FAIL
Programmation Logique
Unification
otherwise:
begin
HE1 := first element of E1;
HE2 := first element of E2;
SUBS1 := unify(HE1, HE2);
if (SUBS1 = FAIL) then return FAIL;
TE1 := apply (SUBS1, rest of E1);
TE2 := apply (SUBS1, rest of E2);
SUBS2 := unify(TE1, TE2);
if (SUBS2 = FAIL)
then return FAIL;
else return composition (SUBS1, SUBS2);
end
end
end.
Programmation Logique
Unification
Exemple :
Programmation Logique
Unification
Programmation Logique
Unification
• Algorithme d’Unification :
• Voici l'algorithme qui retourne un unificateur (le plus général) , s'il existe, et retourne ECHEC sinon :
Exemple:
• Pour savoir qui est une femme, il suffit de
homme(ali).
faire la requête suivante :
homme(mohamed).
?- femme(X).
homme(salah).
X = fatma.
femme(fatma).
X = zohra.
femme(zohra).
X = mouna.
femme(mouna).
• Pour retourner la réponse, l'interprète Prolog
tente d'unifier le but femme(X) avec chacun
pere(salah,ali).
des faits que le programme contient, dans
pere(mohamed,ali).
l'ordre de leur apparition.
pere(mouna,salah).
• L'unification avec le fait homme(ali) échoue,
puisque les deux prédicats sont différents. Il
mere(mouna,zohra).
en sera de même pour les deux faits qui
mere(mohamed,zohra).
suivent.
mere(salah, zohra).
• C'est seulement lorsque l'interprète rencontre
le fait femme(fatma) que l'unification réussit.
mere(zohra,fatma).
Programmation Logique
Unification
• Variables anonymes:
• Une variable anonyme est une variable dont la valeur instanciée après unification nous importe peu.
Une variable anonyme est n'importe quel identificateur commençant par le symbole’_’.
• Par exemple, si on désire seulement savoir si ali a un fils, on peut faire la requête suivante :
?- pere(_,ali).
Yes
• Deux occurrences d'une variable anonyme dans un prédicat sont distinctes.
• Par exemple, si nous désirons seulement savoir s'il existe une mère, nous soumettrons la requête
suivante :
?- mere(_,_).
Yes
• Cette requête n'est pas équivalente à celle-ci :
?- mere(X,X).
No
Programmation Logique
Unification
• Algorithme d’Unification :
• On peut utiliser directement l'opérateur "=" pour unifier deux termes (ou deux expressions prédicatives) :
?- p(X,X) = p(1,W).
?- X = 1.
X = 1
X = 1
W = 1
?- ali = mohamed.
?- p(Y,fun(Y)) = p(toto,Z).
No
Y = toto
Z = fun(toto)
?- suc(X) = suc(suc(suc(0))).
X = suc(suc(0))
?- p(X,X,2) = p(1,W,W).
No
?- p(X,X) = p(1,2).
No
Pour s'assurer que deux termes ne sont pas
unifiables, on utilise l'opérateur \= :
?- p(X,X) = p(1,1).
X = 1
?- p(X,X,2) \= p(1,W,W).
Yes
Programmation Logique
Unification
• Les Structures de Listes: Les structures de listes se présentent comme:
• [1 , 2 , 3] une liste contenant 3 éléments qui sont des constantes,
• [X|T] une liste dont la tête est représentée par la variable X et la queue par la variable
T
• L’unification de [X|T] avec [1 , 2 , 3] conduit à:
? [X|T] = [1 , 2 , 3]
X = 1 , T = [2,3]
?- [1,2|X] = [1,2]
X = []
?- [1,2|X] = [1,2,7,3,4]
X = [7,3,4]
Programmation Logique
Principe de Résolution
• Exécution d’un programme: Algorithme de Résolution
• Les règles d’un programme Prolog ont la forme suivante :
• H :- B1,B2, : : :,Bn
• H et B1,B2, : : :,Bn constituent la tête et le corps de la règle, respectivement.
• La signification d'une règle est la suivante :
• pour résoudre un but H, il faut résoudre la conjonction de buts
• B1,B2, : : :,Bn.
• Un fait peut être considéré comme une clause sans corps.
• Pour satisfaire une requête, l'interpréteur Prolog utilise l'algorithme de résolution,
qui utilise une pile, appelée résolvante, pour contenir tous les buts qui restent à
résoudre
Programmation Logique
Principe de Résolution
• Exécution d’un programme: Algorithme de Résolution
0) Se positionner à la première clause du programme
1) Résolvante = requête
2) Tant que la résolvante n'est pas vide :
2.1) Obj ← Premier objectif de la résolvante
2.2) Retirer le premier objectif de la résolvante
2.3) Chercher la première clause C = H :- B1;B2; : : :Bn telle que H s'unifie avec Obj
Si on réussit
2.4) Ajouter au début de la résolvante tous les buts B1,B2,: : :Bn
2.5) Si il existe d'autres têtes de clauses unifiables avec Obj
Mémoriser la position de la clause C comme dernier point de choix
2.6) Retourner à 2.1
Sinon
2.7) Si il existe des points de choix :
Retourner au dernier point de choix (Backtrack)
Revenir à l'étape 2.3
Sinon :
Retourner ECHEC
3) Retourner l'instantiation des variables de la requête
Programmation Logique
Principe de Résolution
Exemple:
homme(ali).
homme(mohamed).
parents(X,M,P):- mere(X,M), pere(X,P).
homme(salah).
frere(X,Y):- homme(Y), parents(X,M,P),
femme(fatma).
parents(Y,M,P).
femme(zohra).
femme(mouna).
Déroulons l’algorithme pour la requête
pere(salah,ali).
suivante:
pere(mohamed,ali).
pere(mouna,salah).
?- frere(salah, mohmed).
mere(mouna,zohra).
Yes
mere(mohamed,zohra).
mere(salah, zohra).
mere(zohra,fatma).
Programmation Logique
Principe de Résolution
• Algorithme d’Unification :
• La recherche de solutions par Prolog est une recherche non déterministe = recherche de
toutes les solutions possibles,
• l’algorithme de recherche de Prolog repose sur une stratégie « profondeur d’abord» et de «
gauche à droite » dans la considération des buts à atteindre (à effacer) en parcourant les
clauses dans l’ordre de leur apparition dans le programme,
ancetre(X,mohamed)
Exemple:
1 5
ancetre(X,Y) :- parent(X,Z), ancetre(Z,Y).
ancetre(X,X).
parent(X,Z1), ancetre(Z1, mohamed)
parent(ali, mohamed)
2 {X=ali, Z1=mohamed} {X=mohamed}
?- ancetre(X, mohamed)
ancetre(mohamed, mohamed) succès
X=ali ->;
{X=ali}
3 4
X=mohamed ->;
parent(mohamed, Z2), ancetre(Z2, mohamed)
{X=ali, X2=mohamed, Y2=mohamed} {X=ali}
échec succès
Programmation Logique
Principe de Résolution
• Recherche de quelques solutions :
• pour limiter la recherche à quelques solutions, Prolog
fournit un opérateur de coupure de l’arbre de
recherche, l’opérateur « cut » représenté par « ! » ou « /
»
• L’ activation de l’opérateur « cut » quand il est
rencontré comme question courante, provoque le gel
des choix faits, depuis ceux de la situation courante
jusqu’aux points de choix relatifs à la question qui a fait
apparaitre le « cut » parmi la liste des questions,
Programmation Logique
Principe de recherche de solutions
• Recherche de quelques solutions : l’utilisation du « cut »
• Exemple:
ancetre(X,mohamed)
Exemple:
1 5
ancetre(X,Y) :- parent(X,Z), !, ancetre(Z,Y).
parent(X,Z1), !, ancetre(Z1, mohamed)
ancetre(X,X).
2 {X=ali, Z1=mohamed} {X=mohamed}
parent(ali, mohamed)
!, ancetre(mohamed, mohamed) succès
?- ancetre(X, mohamed)
{X=ali}
X=ali ->;
3 4
parent(mohamed, Z2), ancetre(Z2, mohamed)
{X=ali, X2=mohamed, Y2=mohamed} {X=ali}
échec succès
Programmation Logique
Principales problématiques
• La négation par l’échec:
• Les L.P. logiques (dont Prolog) pratiquent la négation par
l'échec, c’est-à-dire que pour démontrer not(F) Prolog va
tenter de démontrer F. Si la démonstration de F échoue,
Prolog considère que not(F) est démontrée.
• Pour Prolog, not(F) signifie que la formule F n’est pas
démontrable, et non que c’est une formule fausse. C ’est ce
que l’on appelle l'hypothèse du monde clos.
• La négation par l'échec ne doit être utilisée que sur des
prédicats dont les arguments sont déterminés et à des fins de
vérification,
Programmation Logique
Principales problématiques
• La négation par l’échec: (suite)
• Dangers :
• Considérez le programme suivant :
p(a).
• Et interrogez Prolog avec :
?- X = b, not p(X).
YES {X = b}
• Prolog répond positivement car p(b) n’est pas démontrable.
• Par contre, interrogez le avec :
?- not p(X), X=b.
NO
• Prolog répond négativement car p(X) étant démontrable avec {X = a}, not p(X) est
considéré comme faux.
Programmation Logique
Principales problématiques
• Utilisation d’information de contrôle dans la
programmation logique:
• L’opérateur « cut » est un mécanisme explicite de contrôle
qui est introduit dans le programme !!!
• Le fait que la stratégie utilisée par Prolog soit la stratégie «
profondeur d’abord » et le choix de parcours linéaire des
buts de «gauche à droite», consiste en une information
implicite de contrôle qui fait que certains programmes
peuvent échouer,
• Exemple, reconsidérer le fonctionnement du programme vu
précédemment avec la clause suivante:
ancetre(X,Y) :- ancetre(Z,Y), parent(X,Z).