Prolog

TD n°5

Exercices sur les listes, suite

  1. efface(X,L,L1) est vrai si la liste L1 est la liste L dont tous les éléments égaux à X ont été effacés.

Application à la Généalogie

Puisque notre but est de traduire les questions du français au Prolog, apres vérification de leur syntaxe (avec l'automate du TD n°4), on procède à une analyse sémantique (rudimentaire) qui consiste ici à éliminer dans un premier temps les mots vides (non pertinents pour la traduction sémantique en Prolog).
  1. Définir un prédicat motVide qui répond vrai si le mot passé en paramètre fait partie des mot inutiles dans le traitement des questions du TD n°4.
  2. Définir un prédicat qui nettoie une question de ses mots vides.
    Pensez à aller revoir au TD n°1 la traduction sémantique des questions qu'on a syntaxiquement analysées.

Méta-prédicats pour construire un prédicat et l'appliquer

Il reste à transformer la liste "nettoyée" en un prédicat qui interroge l'arbre généalogique : par exemple, [pere,babar] en pere(X,babar)
Si on tente directement quelque chose du genre :
reponse([Predicat,Individu],X) :- Predicat(X,Individu).
c'est refusé par Prolog parce que les éléments d'une liste sont des atomes et qu'on n'a pas le droit d'appliquer un atome sur un autre atome.

En SWI, le meta-predicat apply(P,L), quand on lui donne un prédicat P et L une liste contenant le même nombre d'éléments que le nombre d'arguments de P, donne le même résultat que si on avait appliqué P aux éléments de L.
Par exemple apply(homme,[babar]) est vrai car homme(babar) est vrai.
Idem pour apply(pere,[babar,celestine]), etc.

En GNU Prolog, ce meta-prédicat n'existe pas, on va donc procéder autrement, en deux étapes :

  1. On construit un terme avec le constructeur "=..". Ce constructeur attend un terme à gauche et, à droite, une liste dont le premier élément est le nom du foncteur qui sera appliqué, et les éléments suivants ses arguments, dans l'ordre. On peut utiliser ce constructeur dans les deux sens, en mettant une variable à gauche ou à droite. Par exemple :
    ?- T =.. [homme,babar].
    est vrai si T=homme(babar), autrement dit construit le terme homme(babar).
  2. Une fois un terme T construit, on peut, quand ce terme coincide avec une formule logique qui a une valeur de vérité, demander à évaluer cette valeur de vérité avec le meta-prédicat call(T). Ainsi :
    ?- T =.. [homme,babar], call(T).
    donne une réponse vraie si homme(babar) est vrai.
Écrire le prédicat reponse([Predicat,Individu],X) qui est vrai si X est une réponse à la question initiale qui avait été posée : traiter dans un premier temps uniquement les questions sans emboîtement (du genre « qui est le père de babar ? ») qui, après nettoyage, donnent une liste à 2 éléments comme [pere,babar].

Version complète

Même question, mais avec les prédicats avec emboitement (du genre « qui est le cousin du pere de dagobert  ? »). Evidemment, il peut y avoir un nombre non borné d'emboitements donc la définition doit être récursive.

Version finale de l'analyse

Le meta-prédicat setof(X,P(...X...),L), quand on lui donne une variable X et un prédicat P qui depend de X, donne comme resultat la liste L qui contient l'ensemble des valeurs de X qui rendent vraies le prédicat P.
Écrire le prédicat qui analyse une question complète (avec analyse syntaxique et sémantique) et donne sa réponse.

Encore mieux

Voici un petit plus. Si on veut partir d'une question sous la forme d'une vraie chaîne de caractères, et non plus d'une liste, voici un ensemble de prédicats qui transforment une chaine de caractères entre guillemets (« " ») où les mots sont séparés par un nombre quelconque de blancs et se terminant par un « ? » en une liste de mots.
Les nombres qui interviennent dans ces prédicats sont les codes ASCII des caractères spéciaux :
/* lecture au clavier d'une question (reconnue au fait qu'elle se
termine par un point d'interrogation) et transcription en une liste
d'atomes */

vocab([],[]) :- !.
vocab([32|LC],Lex) :- ! , vocab(LC,Lex).        /* élimination des blancs inutiles */
vocab([44|LC],[","|Lex]) :- ! , vocab(LC,Lex).  /* insertion de la virgule */
vocab([63|_],[]) :- !.                          /* on s'arrête dès que l'on rencontre un
                                                   point d'interrogation */
vocab(Liste,[Mot|Lex]) :- mot(Liste,Mot,Suite),
                          vocab(Suite,Lex).

mot([],[],[]).
mot([32|S],[],S) :- !.      /* détection d'un blanc */
mot([C|LC],[C|M],S) :- mot(LC,M,S).

liste([],[]).
liste([Mot|P],[Atome|L]) :- name(Atome,Mot),liste(P,L).

transforme(Phrase,Liste) :- vocab(Phrase,P),liste(P,Liste).
Après cela, si on demande
?- transforme("qui est  le     cousin du pere  de dagobert ?", L).
on obtient
L = [qui, est, le, cousin, du, pere, de, dagobert]
Donc, en l'intégrant dans l'analyse, on peut poser la question sous la forme d'une chaîne entre guillemets, terminée par un "?" (cf. section suivante)

L'application complète

Enfin, plutôt que d'avoir une réponse "brute" avec l'énumération des noms qui répondent à la question, on préférerait avoir une réponse plus conviviale qui reprenne les mots de la question, du genre :
le cousin du pere de dagobert est : clement
Dernière modification : 9/9/2011
Valid HTML 4.01! Valid CSS!