Documente Academic
Documente Profesional
Documente Cultură
Taie Tura
Taie Tura
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).
%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)
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.
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ă.
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.
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ă.