parent(tina, william).
parent(thomas, william).
parent(thomas, sally).
parent(thomas, jeffrey).
parent(sally, andrew).
parent(sally, melanie).
parent(andrew, joanne).
parent(jill, joanne).
parent(joanne, steve).
parent(william, vanessa).
parent(william, patricia).
parent(vanessa, susan).
parent(patrick, susan).
parent(patricia, john).
parent(john, michael).
parent(john, michelle).
parent(frank, george).
parent(estelle, george).
parent(morty, jerry).
parent(helen, jerry).
parent(jerry, anna).
parent(elaine, anna).
parent(elaine, kramer).
parent(george, kramer).
parent(margaret, nevia).
parent(margaret, alessandro).
parent(ana, aleksander).
parent(aleksandr, aleksander).
parent(nevia, luana).
parent(aleksander, luana).
parent(nevia, daniela).
parent(aleksander, daniela).
male(william).
male(thomas).
male(jeffrey).
male(andrew).
male(steve).
male(patrick).
male(john).
male(michael).
male(frank).
male(george).
male(morty).
male(jerry).
male(kramer).
male(aleksandr).
male(alessandro).
male(aleksander).
female(tina).
female(sally).
female(melanie).
female(joanne).
female(jill).
female(vanessa).
female(patricia).
female(susan).
female(michelle).
female(estelle).
female(helen).
female(elaine).
female(anna).
female(margaret).
female(ana).
female(nevia).
female(luana).
female(daniela).
## Družinske relacije
V tem sklopu nalog bomo definirali predikate za nekaj družinskih relacij, kot so »sestra«, »teta« in »prednik«. Za preizkušanje rešitev bomo uporabljali družinsko drevo (pravzaprav gozd), ki ga najdete na učilnici.
Družinske relacije v prologu opišemo s predikati `parent/2`, `male/1` in `female/1`. Zapis `parent/2` pomeni, da gre za predikat z imenom `parent` z dvema argumentoma. Primer:
```Prolog
parent(tina, william).
parent(thomas, william).
parent(thomas, sally).
…
female(tina).
female(sally).
female(vanessa).
…
male(william).
male(thomas).
male(jeffrey).
…
```
Dejstvo `parent(tina, william)` pomeni, da je `tina` starš od `william`a. Imena pišemo z malimi črkami, ker bi jih prolog sicer obravnaval kot spremenljivke.
Nato lahko pišemo različne poizvedbe, npr.:
```Prolog
?- parent(thomas, sally).
true.
?- parent(thomas, X).
X = william ;
X = sally .
```
S podpičjem (`;`) oziroma `n` zahtevamo naslednjo rešitev, s piko (`.`) pa poizvedbo prekinemo. Če se poizvedba ne ustavi, jo prekinemo s `ctrl-c` in nato `a` (za *abort*).
parent(thomas, sally).
parent(thomas, X).
### `mother/2`
Definirajte predikat `mother(X, Y)`, ki velja, ko je `X` mama od `Y`.
```Prolog
?- mother(tina, william).
true.
?- mother(nevia, Y).
Y = luana ;
Y = daniela.
```
% implementiraj predikat mother/2
mother(tina, william).
mother(nevia, Y).
### `grandparent/2`
Definirajte predikat `grandparent(X, Y)`, ki velja, ko je `X` stari starš od `Y`.
```Prolog
?- grandparent(tina, vanessa).
true.
?- grandparent(tina, Y).
Y = vanessa ;
Y = patricia.
```
% implementiraj predikat grandparent/2
grandparent(tina, vanessa).
grandparent(tina, Y).
### `sister/2`
Definirajte predikat `sister(X, Y)`, ki velja, ko je `X` sestra od `Y`.
```Prolog
?- sister(vanessa, Y).
Y = patricia.
```
*Namig:* s predikatom `dif/2` povemo prologu, da sta (oz. naj bosta) dve vrednosti različni. Na primer:
```Prolog
?- dif(X, 2), X = 3.
X = 3.
?- dif(X, 2), X = 2.
false.
```
% implementiraj predikat sister/2
sister(vanessa, Y).
### `aunt/2`
Definirajte predikat `aunt(X, Y)`, ki velja, ko je `X` teta od `Y`.
```Prolog
?- aunt(sally, Y).
Y = vanessa ;
Y = patricia.
```
% implementiraj predikat aunt/2
aunt(sally, Y).
### `ancestor/2`
Definirajte predikat `ancestor(X, Y)`, ki velja, ko je `X` prednik (starš / stari starš / …) od `Y`.
```Prolog
?- ancestor(patricia, Y).
Y = john ;
Y = michael ;
Y = michelle.
```
% implementiraj predikat ancestor/2
ancestor(patricia, Y).
### `descendant/2`
Definirajte predikat `descendant(X, Y)`, ki velja, ko je `X` potomec (otrok / vnuk / …) od `Y`.
```Prolog
?- descendant(patricia, Y).
Y = william ;
Y = tina ;
Y = thomas.
```
% implementiraj predikat descendant/2
descendant(patricia, Y).
## Seznami
Sezname v prologu pišemo z oglatimi oklepaji:
```Prolog
?- L = [1,2,3,4].
```
in lahko vsebujejo karkoli:
```Prolog
?- L = [1, a, foo(4,5), [a,b,c], 3.14].
```
Z združevanjem lahko v seznamu dostopamo do glave (prvega elementa) in repa (preostanka seznama):
```Prolog
?- [H|T] = [1,2,3,4].
H = 1,
T = [2,3,4].
```
Seveda deluje tudi obratno:
```Prolog
?- H = 1, T = [2,3,4], L = [H|T].
L = [1,2,3,4].
```
Dva poljubna seznama lahko staknemo s predikatom `append/3`:
```Prolog
?- append([1,2], [3,4], L).
L = [1,2,3,4].
```
Seveda deluje tudi obratno ~ poiščemo lahko `A` in `B`, ki se stakneta v dani seznam:
```Prolog
?- append(A, B, [1,2,3]).
A = [],
B = [1, 2, 3] ;
A = [1],
B = [2, 3] ;
A = [1, 2],
B = [3] ;
A = [1, 2, 3],
B = [].
```
append(A, B, [1,2,3]).
### `ancestor/3`
Definirajte predikat `ancestor(X, Y, L)`, ki deluje enako kot `ancestor/2`, le da vrne še seznam oseb na poti od `X` do `Y`.
```Prolog
?- ancestor(thomas, vanessa, L).
L = [thomas, william, vanessa].
?- ancestor(thomas, _, L).
L = [thomas, william] ;
L = [thomas, sally] ;
L = [thomas, jeffrey] ;
L = [thomas, william, vanessa] ;
L = [thomas, william, patricia] ;
L = [thomas, william, vanessa, susan] ;
L = [thomas, william, patricia, john] ;
```
Kako bi s pomočjo predikata `ancestor/3` definirali predikata `grandparent/2` in `ancestor/2`?
% implementiraj predikat ancestor/3
ancestor(thomas, vanessa, L).
ancestor(thomas, _, L).
### `member/2`
Definirajte predikat `member(X, L)`, ki velja, ko je `X` element seznama `L`.
```Prolog
?- member(X, [1,2,3]).
X = 1 ;
X = 2 ;
X = 3.
?- member(1, [3,2,X]).
X = 1.
```
% implementiraj predikat member/2
member(X, [1,2,3]).
member(1, [3,2,X]).
### `insert/3`
Definirajte predikat `insert(X, L1, L2)`, ki velja, ko seznam `L2` dobimo tako, da v `L1` vstavimo `X` na poljubno mesto.
```Prolog
?- insert(1, [2,3], L).
L = [1,2,3] ;
L = [2,1,3] ;
L = [2,3,1].
```
% implementiraj predikat insert/3
insert(1, [2,3], L).
### `reverse/2`
Definirajte predikat `reverse(A, B)`, ki velja, ko vsebuje seznam `B` elemente seznama `A` v obratnem vrstnem redu.
```Prolog
?- reverse([1,2,3], X).
X = [3,2,1].
?- reverse([], []).
true.
```
% implementiraj predikat reverse/2
reverse([1,2,3], X).