This is an old revision of the document!


Scopul laboratorului:

  1. TODO
  2. TODO

Cut

Green cut

Red cut

Negation as failure

Colectare rezultate

Fie următoarea bază de cunoștiințe genealogice:

% File: norse.pl
father(buri, borr).
father(borr, odin).
father(borr, vili).
father(borr, ve).
father(odin, thor).
father(odin, baldr).
 
mother(bestla, odin).
mother(bestla, vili).
mother(bestla, ve).
mother(jorth, thor).
mother(frigg, baldr).

Putem defini ușor un predicat pentru a determina relația părinte-copil:

parent(P, C) :- mother(P, C).
parent(P, C) :- father(P, C).

După cum ați observat până acum, predicatul definit e versatil; poate fi folosit pentru a verifica o relație, pentru a determina părinții unei persoane, pentru a determina copiii unei persoane, sau pentru a genera toate perechile părinte-copil din baza de cunoștiințe:

?- parent(odin, thor).
true.

?- parent(buri, odin).
false.

?- parent(borr, C).
C = odin ;
C = vili ;
C = ve.

?-

Pentru ultima interogare, există mai multe posibilități de unificare a variabilei C, iar prolog ni le oferă pe rând (introducând ; interactiv, primim următoarea soluție). Uneori, este util să putem colecta toate aceste soluții într-o listă pe care putem, ulterior, face alte procesări. În continuare, vom studia trei predicate pentru a realiza acest lucru.

findall

findall/3 este un predicat care primește un tipar de rezultate, un goal de demonstrat și o listă de ieșire care va conține toate rezultatele construite pe baza tiparului, pentru care goal-ul primit este adevărat. Cel mai simplu tipar util este o singură variabilă, care se regăsește în scopul primit.

?- findall(C, parent(borr, C), L).
L = [odin, vili, ve].

?-

Dacă nu există niciun rezultat, findall/3 generează o listă vidă:

?- findall(C, parent(baldr, C), L).
L = [].

?-

Deasemenea primul argument poate fi un termen compus:

?- findall(child(C, borr), parent(borr, C), L).
L = [child(odin, borr), child(vili, borr), child(ve, borr)].

?-

bagof

bagof/3 este un predicat asemănător cu findall/3, având aceeași semnificație a parametrilor. Diferența dintre cele două este vizibilă atunci când introducem în goal o variabilă care nu apare în template.

?- findall(C, parent(P, C), L).
L = [odin, vili, ve, thor, baldr, borr, odin, vili, ve|...].

?-

Observăm că findall/3 ne întoarce o singură listă cu toate rezultatele posibile. În unele cazuri, ar fi util ca, pentru fiecare părinte P, să primim o altă listă. Pentru asta folosim bagof:

?- bagof(C, parent(P, C), L).
P = bestla,
L = [odin, vili, ve] ;
P = borr,
L = [odin, vili, ve] ;
P = buri,
L = [borr] ;
P = frigg,
L = [baldr] ;
P = jorth,
L = [thor] ;
P = odin,
L = [thor, baldr].

?-

Rezultatele sunt generate în stilul clasic, necesitând ; interactiv. Putem apoi să le colectăm folosind din nou bagof/3:

?- bagof(children(P, L), bagof(C, parent(P, C), L), R).
R = [children(bestla, [odin, vili, ve]), children(borr, [odin, vili, ve]), children(buri, [borr]), children(frigg, [baldr]), children(jorth, [thor]), children(odin, [thor, baldr])].

?-
În ultima interogare, nu contează dacă predicatul folosit în exterior este bagof/3 sau findall/3. Goal-ul de demonstrat (bagof(C, parent(P, C), L)) nu conține variabile “din afară”.

Ca urmare a felului de funcționare, o diferență notabilă între findall/3 și bagof/3 este că, atunci când goal-ul nu poate fi satisfăcut, findall/3 reușește, generând o listă vidă, iar bagof/3 eșuează.

?- findall(C, parent(thor, C), L).
L = [].

?- bagof(C, parent(thor, C), L).
false.

?-

setof

Fie următorul predicat, pentru a stabili care două persoane au un copil în comun:

common_child(F, M) :- father(F, C), mother(M, C).

Am vrea să generăm o listă cu toate persoanele care au un copil cu Odin. Ne folosim de predicatele bagof/3 și common_child/2:

?- bagof(M, common_child(odin, M), L).
L = [jorth, frigg].

?-

Obținem rezultatul dorit. Ce se întâmplă însă dacă două persoane au în comun mai mulți copii?

?- bagof(M, common_child(borr, M), L).
L = [bestla, bestla, bestla].

?-

Rezultatul nu este ideal, deoarece conține duplicate.

setof/3 este un predicat asemănător cu bagof, având aceeași semnificație a parametrilor, dar care generează o listă sortată, fără duplicate (mai multe informații despre ce implică sortarea, puteți găsi aici).

?- setof(M, common_child(odin, M), L).
L = [frigg, jorth].

?- setof(M, common_child(borr, M), L).
L = [bestla].

?-

În rest, setof/3 se comportă ca bagof/3; pentru variabilele din goal care nu apar în template generează soluții separate și eșuează dacă nu există niciuna:

?- setof(M, common_child(F, M), L).
F = borr,
L = [bestla] ;
F = odin,
L = [frigg, jorth].

?- setof(M, common_child(thor, M), L).
false.

?-

Exerciții