Station MinuitExplorer, comprendre, pratiquer

RAISONNEMENT — Raisonner et résoudreAutomne 2026

Semaine 7 — Logique et raisonnement : récursion et listes Prolog

7. Exercices corrigés et raisonnements

LECTURE 09 / 125 repèresCouverture déclarée complète

7. Exercices corrigés et raisonnements

7.1 Quatre problèmes d’unification

a. f(a,[Z|R]) = f(X,[1,2,3])

Les deux termes ont le même foncteur f/2. Le premier argument impose X=a; le second impose une tête 1 et une queue [2,3]. Résultat : X=a, Z=1, R=[2,3].

b. [L|R] = f(X,g(h(y)))

La structure d’une liste non vide est incompatible avec celle du terme f/2. Résultat : faux, indépendamment de la possibilité de remplacer les arguments internes.

c. L=[V1/O1,V2/O2,X], V1=V2, V2=3, X=1/x, O2=o

Les variables V1 et V2 sont liées entre elles, puis à 3; cette liaison se propage aux deux positions de L. X=1/x reste un terme symbolique, sans division; O2=o précise sa position correspondante. Résultat :

Code (text) · sélectionner pour copier

L = [3/O1, 3/o, 1/x]
V1 = V2 = 3
X = 1/x
O2 = o
O1 reste libre

d. g(x,h(y,59)) = [X|Y]

Même obstacle structurel que pour b : faux. Unifier ne consiste pas à distribuer arbitrairement les composants d’un terme dans une liste.

7.2 Intersection de deux listes

Contrat : inters(L1,L2,LR) produit les éléments de L1 présents dans L2. Exemple officiel actuel :

Code (prolog) · sélectionner pour copier

?- inters([a,12,f,5],[w,a,5,34,12,e],X).
X = [a,12,5].

La vidéo signale une erreur dans une ancienne version de cet exemple; le PDF téléchargé le 16 octobre donne le résultat corrigé ci-dessus.

Le résultat est toujours une liste. Sans élément commun, il faut [], et non 0; deux listes identiques peuvent donner la liste entière. Les positions des éléments dans les deux listes n’ont pas à correspondre : 12 est commun même s’il n’est pas au même indice. On parcourt L1 et, pour chaque tête, on vérifie son appartenance à toute L2.

Code (prolog) · sélectionner pour copier

inters([],L2,[]).
inters([X|L1],L2,[X|LR]) :-
    member(X,L2), inters(L1,L2,LR).
inters([X|L1],L2,LR) :-
    not(member(X,L2)), inters(L1,L2,LR).

Trois cas : la première liste est vide; sa tête appartient à L2 et est gardée; ou sa tête n’y appartient pas et est ignorée. Dans les deux cas non vides, poursuivre sur la queue de L1. La deuxième liste sert de référence et reste inchangée.

Trace de l’exemple : garder a, garder 12, rejeter f, garder 5, puis terminer sur le vide. L’ordre du résultat suit donc L1.

Variante par si-alors-sinon, également fournie :

Code (prolog) · sélectionner pour copier

inters([],L2,[]).
inters([X|L1],L2,LR) :-
    ( member(X,L2)
    -> LR=[X|LRbis], inters(L1,L2,LRbis)
    ;  inters(L1,L2,LR)
    ).

Ces deux définitions sont des alternatives, à tester séparément sous ce nom, plutôt que des clauses à cumuler. Le test décide si la tête doit apparaître dans le résultat. Les appels récursifs traitent la queue dans les deux branches.

Sur les données fixées des exercices, le mécanisme est direct. Pour comprendre ses limites : member/2 unifie et peut donc lier des variables libres; not(...) vérifie l’échec au moment de l’appel. Des doublons de L1 sont conservés; des doublons de L2 peuvent produire plusieurs preuves dans la première version, tandis que -> s’engage sur le premier succès de son test. Ce code ne doit pas être assimilé sans réserve à une intersection ensembliste générale dans tous les modes d’appel.

7.3 Nombre d’occurrences

Contrat : nb_occ(L,X,C) associe C au nombre d’occurrences de X dans L. Cette fois, le résultat est un nombre :

Code (prolog) · sélectionner pour copier

?- nb_occ([a,a,f,d,a],a,N).
N = 3.

Code (prolog) · sélectionner pour copier

nb_occ([],X,0).
nb_occ([X|R],X,C) :- nb_occ(R,X,D), C is D+1.
nb_occ([Y|R],X,C) :- not(X=Y), nb_occ(R,X,C).

Le vide contient zéro occurrence. Si la tête s’unifie à X, compter la queue et ajouter 1. Sinon, compter la queue sans incrément. Pour l’exemple, les contributions sont 1+1+0+0+1=3.

La variable D doit avoir reçu le compte récursif avant C is D+1. Les deux cas de tête sont exclusifs sur les éléments fixés de l’exemple. Avec des variables libres, la clause positive peut créer des liaisons, et not(X=Y) n’est pas une contrainte persistante de différence. Le contrat d’usage doit donc être clair.

7.4 Répartir positifs et négatifs

Contrat : sup_inf(L,S,I) conserve dans S les éléments strictement positifs de L et dans I les strictement négatifs. Les zéros n’apparaissent dans aucune des deux listes.

Code (prolog) · sélectionner pour copier

?- sup_inf([2,12,0,-3,6,-5],S,I).
S = [2,12,6], I = [-3,-5].

Corrigé officiel :

Code (prolog) · sélectionner pour copier

sup_inf([],[],[]).
sup_inf([N|R],S,I) :- N=0, sup_inf(R,S,I).
sup_inf([N|R],[N|S],I) :- N>0, sup_inf(R,S,I).
sup_inf([N|R],S,[N|I]) :- N<0, sup_inf(R,S,I).

Le vide donne deux résultats vides. Un zéro est ignoré; un positif devient tête de S; un négatif devient tête de I. Ignorer zéro ne signifie pas arrêter la récursion : il faut encore examiner tous les éléments de la queue. L’ordre relatif des positifs et celui des négatifs sont conservés. La liste d’entrée n’est pas modifiée en place.

Le code imprimé utilise N=0, unification avec le terme entier 0. Pour les entiers des exemples, cela convient. Un flottant 0.0 n’est toutefois pas le même terme que 0 et n’est ni strictement positif ni strictement négatif : cette version ne couvre donc pas tous les nombres possibles. Une variante destinée à des nombres déjà instanciés peut employer N =:= 0 pour comparer la valeur arithmétique. Cette variante doit rester distinguée de la ligne effectivement donnée dans le corrigé.

Retour au sommaire de l’unitéHaut de page
Récupérer manuellement les données locales

Copier séparément les données ci-dessous dans des fichiers texte avant de fermer la page ou de modifier le stockage. Une valeur illisible ou incompatible reste en place. Aucun effacement ni rétablissement écrasant n’est effectué automatiquement. L’export/import JSON est disponible sur la page Progression du thème. Cette récupération séparée reste utile pour une valeur brute ou un conflit.

Clé de ce cours : . Format v1 porté par cette clé; dates UTC et identifiants durables.

Si l’accès est refusé, la valeur persistée peut rester inaccessible. Réautoriser le stockage dans le navigateur puis rouvrir ce cours permet de la relire. Une réinitialisation exige une décision explicite après récupération; aucune commande de suppression n’est proposée ici. Les données restent sur cette origine et cet appareil, sans transfert automatique.