Vaje: prolog
Priprava okolja
- Ubuntu/Debian:
$ sudo apt install swi-prolog
- ArchLinux:
% sudo pacman -S swi-prolog
- Drugi https://eu.swi-prolog.org/download
- VSCode razširitev:
jeff-hykin.better-prolog-syntax
- SWISH notebooks: https://swish.swi-prolog.org/ (glej Discord)
- Virtualka (glej Discord)
Dodatne "on-line" vaje iz prologa
Te naloge najdete tukaj: https://codeq.si/?s=prolog. Naredite si nov račun.
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:
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.
Datoteko famrel.pl
v prolog naložimo z ukazom
?- ['famrel.pl'].
Nato lahko pišemo različne poizvedbe, npr.:
?- 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).
mother/2
Definirajte predikat mother(X, Y)
, ki velja, ko je X
mama od Y
.
?- mother(tina, william).
true.
?- mother(nevia, Y).
Y = luana ;
Y = daniela.
grandparent/2
Definirajte predikat grandparent(X, Y)
, ki velja, ko je X
stari starš od Y
.
?- grandparent(tina, vanessa).
true.
?- grandparent(tina, Y).
Y = vanessa ;
Y = patricia.
sister/2
Definirajte predikat sister(X, Y)
, ki velja, ko je X
sestra od Y
.
?- sister(vanessa, Y).
Y = patricia.
Namig: s predikatom dif/2
povemo prologu, da sta (oz. naj bosta) dve vrednosti različni. Na primer:
?- dif(X, 2), X = 3.
X = 3.
?- dif(X, 2), X = 2.
false.
aunt/2
Definirajte predikat aunt(X, Y)
, ki velja, ko je X
teta od Y
.
?- aunt(sally, Y).
Y = vanessa ;
Y = patricia.
ancestor/2
Definirajte predikat ancestor(X, Y)
, ki velja, ko je X
prednik (starš / stari starš / …) od Y
.
?- ancestor(patricia, Y).
Y = john ;
Y = michael ;
Y = michelle.
descendant/2
Definirajte predikat descendant(X, Y)
, ki velja, ko je X
potomec (otrok / vnuk / …) od Y
.
?- descendant(patricia, Y).
Y = william ;
Y = tina ;
Y = thomas.
Seznami
Sezname v prologu pišemo z oglatimi oklepaji:
?- L = [1,2,3,4].
in lahko vsebujejo karkoli:
?- 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):
?- [H|T] = [1,2,3,4].
H = 1,
T = [2,3,4].
Seveda deluje tudi obratno:
?- H = 1, T = [2,3,4], L = [H|T].
L = [1,2,3,4].
Dva poljubna seznama lahko staknemo s predikatom append/3
:
?- 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:
?- 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 = [].
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
.
?- 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
?
member/2
Definirajte predikat member(X, L)
, ki velja, ko je X
element seznama L
.
?- member(X, [1,2,3]).
X = 1 ;
X = 2 ;
X = 3.
?- member(1, [3,2,X]).
X = 1.
insert/3
Definirajte predikat insert(X, L1, L2)
, ki velja, ko seznam L2
dobimo tako, da v L1
vstavimo X
na poljubno mesto.
?- insert(1, [2,3], L).
L = [1,2,3] ;
L = [2,1,3] ;
L = [2,3,1].
reverse/2
Definirajte predikat reverse(A, B)
, ki velja, ko vsebuje seznam B
elemente seznama A
v obratnem vrstnem redu.
?- reverse([1,2,3], X).
X = [3,2,1].
?- reverse([], []).
true.