ANNEXE 2 · NLP & PROLOG

Du Langage Naturel aux Triplets

Comment Prolog et les grammaires DCG permettaient de comprendre
le français bien avant que ChatGPT n'existe.
(Et comment ça nous sert encore pour le Web Sémantique.)

Avant les LLM, il y avait Prolog

Aujourd'hui, on balance une phrase à ChatGPT et il « comprend ». Mais comment faisait-on avant ? Dans les années 80 et 90, le traitement du langage naturel (NLP) n'était pas une histoire de réseaux de neurones gargantuesques, mais de grammaires formelles, de logique, et de Prolog.

Cette annexe raconte cette époque — et montre que ces techniques restent profondément utiles pour le Web Sémantique. Parce qu'au fond, le problème est le même : transformer du texte en structures formelles (triplets, graphes RDF, faits logiques). Et Prolog, avec ses Definite Clause Grammars (DCG), fait ça avec une élégance que les LLM ne pourront jamais égaler (parce que les LLM n'ont pas d'élégance, ils ont des poids).

📜 Petite chronologie NLP :
1950 — Turing propose le test de l'imitation (deviendra le Test de Turing)
1957 — Chomsky publie « Syntactic Structures » (grammaires génératives)
1970 — Colmerauer crée Prolog à Marseille (oui, en France !)
1975 — Pereira & Warren inventent les DCG pour Prolog
1987 — IBM traite des réservations vol avec du NLP à base de règles
2003 — Bengio introduit les word embeddings (la fin du règne des règles)
2017 — « Attention is All You Need » : les LLM débarquent
202x — Vous, ici, qui allez comprendre comment on faisait avant 2020
(Et accessoirement, que le NLP à base de règles, c'était du vrai génie logiciel.)
« En Prolog, un programme c'est de la logique. Et une grammaire, c'est juste un programme qui s'exécute à l'envers. » — Alain Colmerauer (créateur de Prolog, résumant la beauté des DCG)
01

NLP — avant que ce soit « juste un API call »

Le Natural Language Processing (TALN en français — Traitement Automatique du Langage Naturel) est le domaine qui cherche à faire comprendre du texte par un ordinateur. Avant 2015, ça ressemblait à ça :

  1. Tokenisation — découper les mots (hello split)
  2. POS tagging — déterminer la nature de chaque mot (nom, verbe, adjectif…) avec des modèles statistiques (HMM, CRF)
  3. Lemmatisation — ramener chaque mot à sa forme canonique (« marchions » → « marcher »)
  4. Analyse syntaxique — construire un arbre grammatical (sujet, verbe, complément) à l'aide d'une grammaire formelle
  5. Analyse sémantique — transformer l'arbre en une représentation logique (prédicats, triplets, formules)
  6. Interprétation — répondre à une question, ajouter des faits à une base, générer un graphe RDF

Les étapes 4 et 5 sont celles qui nous intéressent ici. C'est là que les DCG de Prolog brillent : elles permettent d'écrire une grammaire directement dans le langage, et d'obtenir l'analyse sémantique gratuitement par unification.

🧠 Pourquoi c'est important pour le cours :
Dans le Cours #2, vous construisez un mini-Prolog avec chaînage avant et parseur Turtle. Dans cette annexe, on va voir une autre facette de Prolog : l'analyse de langage naturel. Les deux se rejoignent quand on veut extraire des triplets RDF à partir de phrases françaises — exactement ce qu'on fait quand on alimente une ontologie à partir de textes.
02

Definite Clause Grammars — la grammaire qui se prend pour du code

Une DCG (Definite Clause Grammar) est une notation de grammaire intégrée à Prolog. Elle permet de définir des règles grammaticales avec la même syntaxe que les prédicats Prolog, et d'obtenir automatiquement un parseur (qui analyse) et un générateur (qui produit des phrases).

Grammaire hors-contexte (CFG) classique

Une grammaire hors-contexte décrit la structure d'une langue avec des règles de la forme NonTerminal → Suite de symboles. Exemple minimal :

cfgphrase   →  groupe_nominal, groupe_verbal.
groupe_nominal  →  déterminant, nom.
groupe_verbal   →  verbe, groupe_nominal.
déterminant     →  [le] | [la] | [un] | [une].
nom             →  [chat] | [souris] | [chien].
verbe           →  [mange] | [poursuit] | [voit].

Cette grammaire reconnaît « le chat mange une souris », « un chien poursuit le chat », etc. Mais elle ne fait que vérifier la syntaxe. Elle ne construit pas de sens.

DCG — la même chose, en Prolog

En Prolog, une DCG s'écrit avec --> (au lieu de :-) :

prolog% Règles de grammaire DCG
  phrase      -->  groupe_nominal, groupe_verbal.
  groupe_nominal -->  determinant, nom.
  groupe_verbal  -->  verbe, groupe_nominal.

  determinant -->  [le]  ;  [la]  ;  [un]  ;  [une].
  nom        -->  [chat] ;  [souris] ;  [chien].
  verbe      -->  [mange] ;  [poursuit] ;  [voit].

Et on interroge :

prolog% Analyse : est-ce une phrase valide ?
  ?- phrase([le, chat, mange, une, souris], []).
  true .

  % Génération : produire une phrase aléatoire
  ?- phrase(P, []).
  P = [le, chat, mange, le, chat] ;
  P = [le, chat, mange, le, souris] ;
  P = [le, chat, poursuit, le, chat]  % ...
« Le même programme sert à analyser et à générer. C'est ça, la magie de Prolog : la directionnalité n'est pas dans le code, elle est dans la question qu'on pose. » — Fernando Pereira (co-inventeur des DCG)

Le secret ? Prolog transforme chaque règle DCG en un prédicat avec deux arguments cachés : la liste de mots restante avant et après l'application de la règle. C'est un diff-list — une technique élégante pour parser sans consommer la mémoire.

03

DCG en action : construire un arbre syntaxique

Une DCG peut construire une structure de données pendant l'analyse. Il suffit d'ajouter un argument à chaque règle pour représenter le résultat :

prolog% DCG avec construction de l'arbre syntaxique
  phrase(phrase(GN, GV))  -->  groupe_nominal(GN), groupe_verbal(GV).
  groupe_nominal(gn(D, N)) -->  determinant(D), nom(N).
  groupe_verbal(gv(V, GN)) -->  verbe(V), groupe_nominal(GN).

  determinant(le)    -->  [le].
  determinant(un)    -->  [un].
  nom(chat)           -->  [chat].
  nom(souris)         -->  [souris].
  verbe(mange)         -->  [mange].
  verbe(poursuit)      -->  [poursuit].

Résultat :

prolog?- phrase(Arbre, [le, chat, poursuit, une, souris], []).
  Arbre = phrase(gn(le, chat), gv(poursuit, gn(une, souris)))

  % On peut visualiser l'arbre :
  %         phrase
  %        /      \
  %      gn        gv
  %     /  \      /  \
  %   le  chat  poursuit  gn
  %                  /  \
  %                une  souris

À ce stade, on a un parseur syntaxique complet en 15 lignes de Prolog. Pas de bibliothèque externe, pas de JSON, pas d'API. Juste une grammaire et le moteur d'unification.

Ajout de la sémantique

Le vrai pouvoir des DCG, c'est qu'on peut directement produire une représentation sémantique pendant l'analyse. Au lieu de construire un arbre, on construit des prédicats logiques :

prolog% DCG qui produit directement des faits logiques
  phrase(sujet_verbe_objet(S, V, O)) -->
      sujet(S), verbe(V), objet(O).

  sujet(socrate)  -->  [socrate].
  sujet(platon)   -->  [platon].
  verbe(est)      -->  [est].
  objet(mortel)   -->  [mortel].
  objet(un_homme) -->  [un, homme].

  % Utilisation :
  ?- phrase(Triplet, [socrate, est, mortel], []).
  Triplet = sujet_verbe_objet(socrate, est, mortel).

Ce sujet_verbe_objet(socrate, est, mortel) ressemble furieusement à un triplet RDF (socrate rdf:type mortel). Coïncidence ? Pas du tout.

04

Du français aux triplets RDF — l'étape ultime

Le Web Sémantique est basé sur des triplets (sujet, prédicat, objet). On peut écrire une DCG qui, à partir d'une phrase française, produit directement un triplet ou même un graphe RDF complet.

Grammaire complète français→triplet

prolog% ------------------ LEXIQUE ------------------
  det   --> [le] ; [la] ; [un] ; [une] ; [les] ; [des].

  nom(chat)    --> [chat] ; [chats].
  nom(souris)  --> [souris].
  nom(socrate) --> [socrate].
  nom(homme)   --> [homme].

  verbe_intrans(existe)  --> [existe].
  verbe_trans(mange)    --> [mange].
  verbe_copule(est)     --> [est] ; [sont].

  propriete(mortel)  --> [mortel].    % adjectif attribut

  % ------------------ RÈGLES ------------------

  % Sujet Verbe : "Socrate existe"
  % → triplet(Sujet, rdf:type, Classe)
  phrase(triplet(S, type, C)) -->
      sujet(S), verbe_intrans(existe).

  % Sujet Verbe_Être Propriété : "Socrate est mortel"
  % → triplet(Sujet, rdf:type, Propriete)
  phrase(triplet(S, type, P)) -->
      sujet(S), verbe_copule(est), propriete(P).

  % Sujet Verbe Objet : "le chat mange une souris"
  % → triplet(Sujet, verbe, Objet)
  phrase(triplet(S, V, O)) -->
      sujet(S), verbe_trans(V), objet(O).

  sujet(N)  --> nom(N).
  sujet(N)  --> det, nom(N).
  objet(N)  --> nom(N).
  objet(N)  --> det, nom(N).

Testons :

prolog?- phrase(T, [socrate, est, mortel], []).
  T = triplet(socrate, type, mortel)

  ?- phrase(T, [socrate, existe], []).
  T = triplet(socrate, type, existe)

  ?- phrase(T, [le, chat, mange, une, souris], []).
  T = triplet(chat, mange, souris)

  % On peut même générer des phrases à partir de triplets !
  ?- phrase(triplet(socrate, type, mortel), Phrase, []).
  Phrase = [socrate, est, mortel]

Bim. Une DCG de 20 lignes qui transforme du français en triplets, et réciproquement. C'est ça, la puissance de Prolog : un programme = deux directions.

Génération du graphe RDF complet

On peut pousser plus loin : une phrase comme « le chat poursuit une souris » peut générer plusieurs triplets, dont un nœud anonyme pour l'événement :

ttl# Résultat RDF :
  []  a            :Poursuite ;
      :agent       :chat ;
      :patient     :souris .
  :chat   a        :Chat .
  :souris a        :Souris .

En Prolog, on ajoute simplement un argument supplémentaire à la DCG pour collecter la liste des triplets générés par la phrase. Chaque règle grammaticale ajoute ses triplets à la liste, et à la fin on a un graphe RDF complet.

Phrase : "Socrate est un homme" │ ▼ DCG parse ──→ [triplet(socrate, type, homme)] │ ▼ Conversion ──→ <http://ex.org/socrate> rdf:type <http://ex.org/homme> . │ ▼ Base de faits ──→ On peut raisonner dessus (cf. Cours #2 & #3) (Prolog ou OWL)

C'est exactement ce que fait le Cours #2 quand il construit des faits Prolog à partir de triplets, ou le Cours #3 quand il charge une ontologie OWL et infère de nouvelles connaissances. La différence est que là, on part du langage naturel au lieu de fichiers Turtle.

🤯 Et la génération de texte alors ?
Oui, les DCG marchent aussi dans l'autre sens : on peut générer une phrase française à partir d'un triplet RDF. C'est la base des premiers systèmes de génération de langage naturel (NLG) dans les années 80. Par exemple, un triplet triplet(chat, mange, souris) peut produire « le chat mange la souris », « un chat mange une souris », etc. Les LLM font la même chose aujourd'hui, mais avec 175 milliards de paramètres. Les DCG le faisaient avec 20 lignes. (Bon, les résultats n'étaient pas aussi fluides, mais l'élégance…)
05

Pourquoi c'était génial (et pourquoi ça compte encore)

Les DCG et le NLP à base de règles sont largement remplacés par les LLM aujourd'hui. Mais les idées n'ont pas disparu — elles sont devenues les fondations silencieuses du NLP moderne.

Approche DCG / règlesÉquivalent moderne (LLM)
Grammaire explicite, transparente, débogable Boîte noire : on ne sait pas pourquoi la réponse est celle-ci
Pas besoin de données d'entraînement Nécessite des milliards de tokens et des GPU à 30 000 €
Production déterministe et reproductible Stochastique : deux exécutions peuvent donner des résultats différents
Génération et analyse dans le même programme Génération oui, analyse « formelle » non (pas de garantie)
Passe à l'échelle horizontalement (un Prolog ça tient sur un Raspberry Pi) Passe à l'échelle verticalement (besoin de datacenters)

Les DCG ne sont pas mortes. Elles survivent dans :

« Les LLM sont impressionnants, mais ce sont des perroquets statistiques. Les DCG, c'est de la linguistique qui marche. Les deux ont leur place. » — Un chercheur en TALN qui a connu les deux époques

Et dans le cours de Web Sémantique ?

Le cours #2 construit un mini-Prolog capable de chaînage avant et de parsing de fichiers Turtle. Les DCG montrent une autre application de Prolog directement utile au cours :

Parseur Turtle

Le format Turtle (sujet predicat objet .) est exactement le genre de langage qu'une DCG peut parser. Sujet-Verbe-Objet en RDF, c'est la même structure que Sujet-Verbe-Complément en grammaire.

Extraction de triplets

Une DCG pourrait transformer un corpus de phrases françaises en une base de triplets RDF, prête à être importée dans Fuseki (Cours #3) ou interrogée en SPARQL (Cours #5).

Raisonnement

Les triplets extraits par la DCG peuvent alimenter le moteur de raisonnement OWL du Cours #3 : les faits deviennent des axiomes, et les inférences enrichissent le graphe.

Génération de phrases

Inversement, un triplet RDF peut être transformé en phrase française par la même DCG. C'est un début de NLG (Natural Language Generation) pour expliquer les résultats SPARQL en français.

🎯 Le message à retenir :
Avant les LLM, on faisait du NLP avec du vrai génie logiciel : des grammaires formelles, de l'unification, de la logique. Prolog et les DCG en sont l'incarnation parfaite. 20 lignes suffisent pour transformer une phrase en triplet RDF. C'est élégant, c'est lisible, c'est déterministe, et ça tourne sur un microcontrôleur.

Dans le cours de Web Sémantique, on fait la même chose : on prend du texte (Cours #1), on le structure en triplets (Cours #2), on le raisonne (Cours #3), on maîtrise Turtle (Cours #4), et on le déploie (Cours #5). Les DCG sont le chaînon manquant entre le langage naturel et le graphe de connaissances. Et maintenant, vous savez les utiliser.
phrase(P, [socrate, est, mortel], []).
P = triplet(socrate, type, mortel)