Sunteți pe pagina 1din 5

Să presupunem că definim următoarele fapte:

preda(dr_Raul, fp).
preda(dr_Raul, plf).
preda(dr_Raul, map).
preda(dr_Iulia, oop).

studiaza(larisa, plf).
studiaza(cosmin, plf).
studiaza(tudor, map).
studiaza(adrian, plf).
studiaza(lorena, oop).

%numele studenților sunt scrise cu litera mica pentru a nu fi considerate


variabile

Să definim predicatul studenti

%studenti(P:profesor, S: student)
%model de flux (i, o)
studenti(P, S):-
preda(P, Curs),
studiaza(S, Curs).
Dacă apelăm studenti(dr_Raul, S) Prolog ne va returna pe rând: larisa, cosmin, adrian, tudor.
Ce se întâmplă în spate?
P va fi dr_Raul, S va fi output.
preda(dr_Raul, Curs) => Curs va fi legat la fp.
Studiaza(S, fp) => false (niciun student nu studiază fp).
Prolog se întoarce la preda, dezleagă Curs de fp și încearcă să-i găsească altă valoare (asta-i procesul de
backtacking).
preda(dr_Raul, Curs) => Curs va fi legat la plf.
studiaza(S, plf) => S va fi legat la larisa.
Prolog raporteaza soluția S = larisa. Dacă apăsăm ; (spunând lui Prolog să continue căutarea)
backtrackingul se întoarce la studiaza(S, plf). S va fi dezlegat de larisa, și Prolog încearcă să caute altă
potrivire.
studiaza(S, plf) => S va fi legat la cosmin.
Prolog raportează soluția S = cosmin. Dacă apăsăm ; backtrackingul se întoarce la studiaza(S, plf). S va fi
dezlegat de cosmin și Prolog încearcă să caute altă potrivire.
studiaza(S, plf) => S va fi legat la adrian (tudor nu e potrivire pentru că nu studiaza
cursul plf).
Prolog raportează soluția S = adrian. Dacă apăsăm ; backtrackingul se întoarce la studiaza(S, plf). S va fi
dezlegat de adrian și Prolog încearcă să caute altă potrivire.
studiaza(S, plf) => false (nu mai sunt studenți care să studieze plf).
Prolog se întoarce la preda, dezleagă Curs de plf și încearcă să găsească altă potrivire.
preda(dr_Raul, Curs) => Curs va fi legat la map. Acum că avem o valoare pentru Curs,
mergem înainte, la studiaza.
studiaza(S, map) => S = tudor
Prolog raportează soluția S = tudor. Dacă apăsăm ; backtrackingul se întoarce la studiaza(S, map). S va fi
dezlegat de tudor și Prolog încearcă să caute altă potrivire.
studiaza(S, map) => false
Ne întoarcem la preda.
preda(dr_Raul, Curs) => false
Nu mai sunt soluții.

Azi am discutat că tăietura (!) semnalizează Prologului că suntem pe clauza bună și să nu mai încerce alte
clauze. Predicatul studenti are o singură clauză, deci, pe baza celor de mai sus, cu sau fără tăietură
funcționează la fel. Ba mai mult, putem pune tăietura oriunde (nu avem condiții). Totuși, dacă adăugăm
o taietură rezultatul va fi diferit, nu doar vom avea alt rezultat comparat cu varianta fără tăietură, dar
vom avea rezultate diferite în funcție de unde punem tăietura. Motivul este următorul: tăietura (pe
lângă cele discutate, și anume că împiedică Prologul să încerce alte clauze), împiedică Prolog să facă
backtracking pe clauza curentă pentru subgoal-uri de dinaintea tăieturii.

Încercați să vă dați seama ce o să returneze următoarele variante de definiție pentru studenti (veti avea
răspunsul și explicația după cele 3 bucăți de cod)

%Studenti(P:profesor, S: student)- Varianta 1


%model de flux (i, o)
studenti(P, S):-
!,
preda(P, Curs),
studiaza(S, Curs).

%Studenti(P:profesor, S: student) – Varianta 2


%model de flux (i, o)
studenti(P, S):-
preda(P, Curs),
!,
studiaza(S, Curs).

%Studenti(P:profesor, S: student) – Varianta 3


%model de flux (i, o)
studenti(P, S):-
preda(P, Curs),
studiaza(S, Curs),
!.
Varianta 1.
Care e efectul tăieturii?
1. Nu încercăm alte clauze (nici nu sunt).
2. Nu facem backtracking pentru subgoaluri de dinaintea tăieturii. Nu avem nimic înaintea
tăieturii, deci rezultatul va fi la fel ca pentru varianta fără tăietură (larisa, cosmin, adrian,
tudor)

Varianta 2.
Care e efectul tăieturii?
1. Nu încercăm alte clauze (nici nu sunt).
2. Nu facem backtracking pe preda, Curs rămâne legat la prima valoare pe care o primește.
Prima valoare pentru Curs era fp. Din moment ce studiaza(S, fp) returnează false, și din
moment ce nu facem backtracking pentru preda, rezultatul final va fi false.
Varianta 3.
Care e efectul tăieturii?
1. Nu încercăm alte clauze (nici nu sunt).
2. Nu facem backtracking nici pe preda, nici pe studiaza, după ce ajungem la tăietura. Curs
inițial va fi fp și studiaza returnează fals. Pentru că încă nu am ajuns la tăietură (nu am trecut
de studiaza) facem backtracking pentru preda și Curs va deveni plf. S va fi larisa. Ajungem la
tăietură. Din acest moment nu mai facem backtracking nici pe preda, nici pe studiaza. Prolog
raportează S = larisa soluție, și nimic altceva.

De ce nu a mers prima implementare de la seminarul 2?

La seminar am avut predicatul nrap implementat în modul următor:

nrap([],_,0):-!.
nrap([H|T],E,R):-
H=:=E,
nrap(T,E,R1),
R is R1 + 1, !.
nrap([_|T],E,R):-
nrap(T,E,R).
Avem tăietură pe primele 2 clauze. Nu avem predicate nedeterministe, deci efectul 2 al tăieturii (că nu
facem backtracking pe subgoaluri de dinaintea tăieturii) nu ne interesează. Am zis că nrap funcționează
cu 2 modele de flux: (i,i,o) și (i,i,i).
Pe noi ne interesează acum clauza a 2-a.
Ce se întâmplă la modelul de flux (i,i,o)?
- H, T, E sunt input, deci sunt legate la valori
- R este output, este liberă
- H=:=E – H și E sunt legate, Prolog verifică dacă sunt legate la aceeași valoare. Dacă da,
mergem mai departe pe clauza curentă, dacă nu, mergem pe clauza 3.
- Presupunând că H și E sunt legate la aceeași valoare, facem apel recursiv cu model de flux
(i,i, o) – T și E sunt legate, R1 e liberă. Când apelul se termină, R1 va fi legat la o valoare.
- R is R1+ 1 – R e variabilă liberă, deci va fi legată la valoarea R1 + 1.
- Întâlnim tăietura, deci nu mergem pe clauza următoare.
- Se termină clauza, valoarea din R va fi raportată ca soluție.
De observat că odată ce am trecut de H =:=E, sigur vom ajunge la tăietură și sigur nu vom intra pe a 3-a
clauză. După condiție H=:=E până la tăietură nu avem nimic care ar putea returna false, și ar putea
împiedica să ajungem la tăietură.

Ce se întâmplă pe modelul de flux (i,i,i)?


- H, T, E, R sunt legate
- H=:=E – H și E sunt legate, Prolog verifică dacă sunt legate la aceeași valoare. Dacă da,
mergem mai departe pe clauza curentă, dacă nu, mergem pe clauza 3.
- Presupunând că H și E sunt legate la aceeași valoare, facem apel recursiv cu model de flux (i,
i, o) – T și E sunt legate, R1 e liberă. Când apelul se termină, R1 va fi legat la o valoare.
- R is R1+ 1 – R e variabilă legată, deci Prolog verifică dacă valoarea lui R este R1 + 1. Dacă
valorile sunt egale, mergem mai departe, ajungem la tăietură și nu încercăm altă clauză.
Dacă valorile nu sunt egale, nu ajungem la tăietură și vom merge la clauza a 3-a, chiar dacă
H era egal cu E. De aici avem problema.
De observat că odată ce am trecut de H =:= E, NU e sigur că vom ajunge la tăietură, dacă R nu este egal
cu R1 + 1 vom abandona această clauză și vom merge pe clauza a 3-a.

Soluția este să mutăm tăietura înainte de R is R1 + 1, să ne asigurăm că dacă H =:= E sigur vom ajunge la
tăietura.

Și încă un exemplu despre cum poate să ne încurce tăietura (plus lipsa condițiilor și scrierea
compactă/elegantă a clauzelor).

Să definim predicatul maxim, care primește 2 numere și returnează valoarea mai mare.

%max(A:int, B:int, M:int)


%model de flux (i, i, o) (i, i, i)
max(A, B, A):- A >= B.
max(A, B, B):- B > A.
Varianta asta funcționează corect. Dar ne putem gândi să eliminăm condiția de pe clauza a 2-a și să
punem tăietură pe prima clauză, după condiție.

%max(A:int, B:int, M:int)


%model de flux (i, i, o) (i, i, i)
max(A, B, A):- A >= B, !.
max(A, B, B).
Pare a fi la fel (pe clauza a 2-a A e singleton variable și poate fi înlocuit cu _, dar în rest pare a fi același
predicat). Și cât timp folosim cu modelul de flux (i,i,o) funcționează bine. Dar ce se întâmplă dacă
trecem la (i,i,i)?
Ce se întâmplă dacă apelăm max(6, 3, 3) ?
max(6, 3, 3)
- Prolog încearcă prima clauză. A va fi 6, B va fi 3 și la parametrul 3 avem inegalitate. Prolog se
așteaptă la 6 (folosesc parametrul A care este legat la 6) dar am 3. Abandonăm clauza și
mergem la clauza a 2-a.
- A va fi 6, B va fi 3, și pentru parametrul 3 avem egalitate: B este legată la 3 și parametrul
nostru este 3. Deci aici totul e bine, și Prolog returnează true.
max(6, 3, 3).
true.
Deși maximul dintre 6 și 3 evident că nu este 3.

Motivul e oarecum similar cu ce am avut înainte (la seminar). Tăietura nu își face efectul, dacă execuția
nu ajunge până la tăietură.

Există 2 soluții pentru problema cu max:


1. Adăugăm condiție și pe clauza a 2-a.
2. Modificăm prima clauză să nu fie atât de compactă și folosim alt parametru pentru rezultat:
Max(A, B, C):- A >= B, !, C = A.
Așa merge și cu model de flux (i,i,i), pentru că am A, B și C care vor avea valoare, se verifică ca A
să fie mai mare ca B, ajungem la tăietură, deci nu mai mergem pe clauza 2, și după aceea verificăm dacă
A și C sunt egale sau nu.

S-ar putea să vă placă și